mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-21 03:16:54 +02:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e930657bf6 | |||
| 0ad9149c90 | |||
| 25f2699523 | |||
| a849f25376 | |||
| fa51da4d76 | |||
| 6b79b7a003 | |||
| 102a10f0fe |
@@ -135,6 +135,10 @@ bool ReadbackLinearImagesEnabled() {
|
||||
return g_config->readback_linear_images;
|
||||
}
|
||||
|
||||
bool TessellationEnabled() {
|
||||
return g_config->tessellation_enabled;
|
||||
}
|
||||
|
||||
bool PlayGoHackEnabled() {
|
||||
return g_config->playgo_hack_enabled;
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@ struct ConfigOptions {
|
||||
bool gpu_assisted_validation_enabled = false;
|
||||
bool renderdoc_enabled = false;
|
||||
bool readback_linear_images = false;
|
||||
bool tessellation_enabled = false;
|
||||
bool playgo_hack_enabled = false;
|
||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||
bool red_zone_protection_enabled = false;
|
||||
@@ -110,6 +111,7 @@ bool GpuAssistedValidationEnabled();
|
||||
|
||||
bool RenderDocEnabled();
|
||||
bool ReadbackLinearImagesEnabled();
|
||||
bool TessellationEnabled();
|
||||
bool PlayGoHackEnabled();
|
||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||
bool RedZoneProtectionEnabled();
|
||||
|
||||
@@ -26,6 +26,10 @@ enum class PrimitiveType : uint32_t {
|
||||
kPolygon = 21,
|
||||
};
|
||||
|
||||
constexpr bool IsRectList(PrimitiveType type) {
|
||||
return type == PrimitiveType::kRectList || type == PrimitiveType::kRectListLegacy;
|
||||
}
|
||||
|
||||
enum class IndexType : uint32_t {
|
||||
kIndex16 = 0,
|
||||
kIndex32 = 1,
|
||||
|
||||
@@ -755,8 +755,7 @@ PipelineCache::Pipeline& PipelineCache::GetGraphicsPipeline(
|
||||
static_params.depth_bounds_test_enable = depth.depth_bounds_test_enable;
|
||||
static_params.depth_min_bounds = depth.depth_min_bounds;
|
||||
static_params.depth_max_bounds = depth.depth_max_bounds;
|
||||
const bool rect_list =
|
||||
command.GetUserConfig().GetPrimType() == Prospero::PrimitiveType::kRectList;
|
||||
const bool rect_list = Prospero::IsRectList(command.GetUserConfig().GetPrimType());
|
||||
static_params.cull_back = !rect_list && mc.cull_back;
|
||||
static_params.cull_front = !rect_list && mc.cull_front;
|
||||
static_params.face = mc.face;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common.h"
|
||||
#include "common/emulatorConfig.h"
|
||||
#include "common/file.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/profiler.h"
|
||||
@@ -789,8 +790,7 @@ static void SetDrawDebugPhase(CommandBuffer& buffer, uint64_t submit_id, const D
|
||||
draw.instance_count, draw.first_instance);
|
||||
}
|
||||
|
||||
static bool GetDrawTopology(const HW::UserConfig& ucfg, bool auto_draw,
|
||||
vk::PrimitiveTopology& topology) {
|
||||
static bool GetDrawTopology(const HW::UserConfig& ucfg, vk::PrimitiveTopology& topology) {
|
||||
|
||||
topology = vk::PrimitiveTopology::ePointList;
|
||||
|
||||
@@ -813,14 +813,11 @@ static bool GetDrawTopology(const HW::UserConfig& ucfg, bool auto_draw,
|
||||
topology = vk::PrimitiveTopology::eTriangleStrip;
|
||||
break;
|
||||
case Prospero::PrimitiveType::kPatch:
|
||||
if (!Config::TessellationEnabled()) return false;
|
||||
[[fallthrough]];
|
||||
case Prospero::PrimitiveType::kRectList:
|
||||
topology = vk::PrimitiveTopology::ePatchList;
|
||||
break;
|
||||
case Prospero::PrimitiveType::kRectListLegacy:
|
||||
if (!auto_draw) {
|
||||
EXIT("unknown primitive type: %u\n", static_cast<uint32_t>(ucfg.GetPrimType()));
|
||||
}
|
||||
topology = vk::PrimitiveTopology::eTriangleStrip;
|
||||
topology = vk::PrimitiveTopology::ePatchList;
|
||||
break;
|
||||
case Prospero::PrimitiveType::kQuadListLegacy:
|
||||
topology = vk::PrimitiveTopology::eTriangleFan;
|
||||
@@ -999,8 +996,7 @@ static void LogDrawStateIfNeeded(const CommandBuffer& buffer, const DrawCallInfo
|
||||
return;
|
||||
}
|
||||
|
||||
if (!draw.IsIndexed() &&
|
||||
buffer.GetUserConfig().GetPrimType() != Prospero::PrimitiveType::kRectListLegacy) {
|
||||
if (!draw.IsIndexed() && !Prospero::IsRectList(buffer.GetUserConfig().GetPrimType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1013,8 +1009,7 @@ static void LogDrawStateIfNeeded(const CommandBuffer& buffer, const DrawCallInfo
|
||||
}
|
||||
|
||||
static void EmitDrawPrimitives(const HW::UserConfig& ucfg, vk::CommandBuffer vk_buffer,
|
||||
const ShaderVertexInputInfo& vs_input_info, const DrawCallInfo& draw,
|
||||
const DrawEmitInfo& emit) {
|
||||
const DrawCallInfo& draw, const DrawEmitInfo& emit) {
|
||||
switch (ucfg.GetPrimType()) {
|
||||
case Prospero::PrimitiveType::kPointList:
|
||||
case Prospero::PrimitiveType::kLineList:
|
||||
@@ -1023,6 +1018,7 @@ static void EmitDrawPrimitives(const HW::UserConfig& ucfg, vk::CommandBuffer vk_
|
||||
case Prospero::PrimitiveType::kTriFan:
|
||||
case Prospero::PrimitiveType::kTriStrip:
|
||||
case Prospero::PrimitiveType::kRectList:
|
||||
case Prospero::PrimitiveType::kRectListLegacy:
|
||||
case Prospero::PrimitiveType::kPatch:
|
||||
if (draw.IsIndexed()) {
|
||||
vk_buffer.drawIndexed(draw.index_count, draw.instance_count, 0, emit.vertex_offset,
|
||||
@@ -1032,14 +1028,6 @@ static void EmitDrawPrimitives(const HW::UserConfig& ucfg, vk::CommandBuffer vk_
|
||||
emit.first_instance);
|
||||
}
|
||||
break;
|
||||
case Prospero::PrimitiveType::kRectListLegacy:
|
||||
if (draw.IsIndexed()) {
|
||||
EXIT("unknown primitive type: %u\n", static_cast<uint32_t>(ucfg.GetPrimType()));
|
||||
}
|
||||
// Sarah
|
||||
EXIT_NOT_IMPLEMENTED(!(draw.index_count == 3 && vs_input_info.buffers_num == 0));
|
||||
vk_buffer.draw(4, draw.instance_count, emit.first_vertex, emit.first_instance);
|
||||
break;
|
||||
case Prospero::PrimitiveType::kQuadListLegacy:
|
||||
EXIT_NOT_IMPLEMENTED((draw.index_count & 0x3u) != 0);
|
||||
for (uint32_t i = 0; i < draw.index_count; i += 4) {
|
||||
@@ -1182,7 +1170,7 @@ void RenderExecutor::ExecutePreparedDraw(uint64_t submit_id, CommandBuffer& buff
|
||||
if (mesh_active) {
|
||||
vk_buffer.drawMeshTasksEXT(mesh_groups, draw.instance_count, 1);
|
||||
} else {
|
||||
EmitDrawPrimitives(ucfg, vk_buffer, state.vertex_info[0], draw, emit);
|
||||
EmitDrawPrimitives(ucfg, vk_buffer, draw, emit);
|
||||
}
|
||||
|
||||
if (!draw.IsIndexed()) {
|
||||
@@ -1258,7 +1246,7 @@ void RenderExecutor::DrawIndex(uint64_t submit_id, CommandBuffer& buffer,
|
||||
hw_check(buffer);
|
||||
|
||||
vk::PrimitiveTopology topology = vk::PrimitiveTopology::ePointList;
|
||||
if (!GetDrawTopology(ucfg, false, topology)) {
|
||||
if (!GetDrawTopology(ucfg, topology)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1368,7 +1356,7 @@ void RenderExecutor::DrawAuto(uint64_t submit_id, CommandBuffer& buffer, const D
|
||||
args.vertex_count, args.instance_count, args.first_instance};
|
||||
|
||||
vk::PrimitiveTopology topology = vk::PrimitiveTopology::ePointList;
|
||||
if (!GetDrawTopology(ucfg, true, topology)) {
|
||||
if (!GetDrawTopology(ucfg, topology)) {
|
||||
ResetBindings();
|
||||
return;
|
||||
}
|
||||
@@ -1378,7 +1366,7 @@ void RenderExecutor::DrawAuto(uint64_t submit_id, CommandBuffer& buffer, const D
|
||||
return;
|
||||
}
|
||||
|
||||
const bool rect_list = ucfg.GetPrimType() == Prospero::PrimitiveType::kRectList;
|
||||
const bool rect_list = Prospero::IsRectList(ucfg.GetPrimType());
|
||||
if (rect_list && state.vertex_info[0].buffers_num == 0 &&
|
||||
state.vertex_info[0].stage.program->param_export_mask == 0 &&
|
||||
state.ps_input_info.input_num != 0) {
|
||||
|
||||
@@ -125,6 +125,7 @@ bool IsRuntimeUniformOp(ValueOpcode op) {
|
||||
case ValueOpcode::ULessThan32:
|
||||
case ValueOpcode::IEqual32:
|
||||
case ValueOpcode::UGreaterThan32:
|
||||
case ValueOpcode::SGreaterThanEqual32:
|
||||
case ValueOpcode::INotEqual32:
|
||||
case ValueOpcode::LogicalOr:
|
||||
case ValueOpcode::LogicalAnd:
|
||||
@@ -930,6 +931,13 @@ private:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case ValueOpcode::SGreaterThanEqual32:
|
||||
if (binary()) {
|
||||
result = std::bit_cast<int32_t>(static_cast<uint32_t>(a)) >=
|
||||
std::bit_cast<int32_t>(static_cast<uint32_t>(b));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case ValueOpcode::LogicalAnd:
|
||||
if (binary()) {
|
||||
result = (a != 0u) && (b != 0u);
|
||||
|
||||
@@ -167,6 +167,12 @@
|
||||
<property name="text"><string>Enable readback</string></property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QCheckBox" name="checkBox_tessellation">
|
||||
<property name="toolTip"><string>Draw tessellated geometry. Disabled by default; unsupported tessellation may cause crashes.</string></property>
|
||||
<property name="text"><string>Enable tessellation support (experimental)</string></property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -275,13 +281,13 @@
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_amd_cpu">
|
||||
<property name="toolTip"><string>Patch CPU instructions that differ between AMD and the host CPU.</string></property>
|
||||
<property name="text"><string>AMD CPU patch (EXPERIMENTAL)</string></property>
|
||||
<property name="text"><string>AMD CPU patch (experimental)</string></property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_red_zone_protection">
|
||||
<property name="toolTip"><string>Helps prevent crashes in some games on Windows</string></property>
|
||||
<property name="text"><string>Windows SysV red zone crash protection (Experimental)</string></property>
|
||||
<property name="text"><string>Windows SysV red zone crash protection (experimental)</string></property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
||||
@@ -92,6 +92,7 @@ public:
|
||||
int gpu_index = -1;
|
||||
bool fullscreen_enabled = false;
|
||||
bool readback_linear_images = false;
|
||||
bool tessellation_enabled = false;
|
||||
int vblank_frequency = 60;
|
||||
int console_language = DEFAULT_CONSOLE_LANGUAGE;
|
||||
bool vulkan_validation_enabled = false;
|
||||
@@ -122,6 +123,7 @@ public:
|
||||
gpu_index = other.gpu_index;
|
||||
fullscreen_enabled = other.fullscreen_enabled;
|
||||
readback_linear_images = other.readback_linear_images;
|
||||
tessellation_enabled = other.tessellation_enabled;
|
||||
vblank_frequency = other.vblank_frequency;
|
||||
console_language = other.console_language;
|
||||
vulkan_validation_enabled = other.vulkan_validation_enabled;
|
||||
@@ -169,6 +171,7 @@ public:
|
||||
KYTY_CFG_SET(gpu_index);
|
||||
KYTY_CFG_SET(fullscreen_enabled);
|
||||
KYTY_CFG_SET(readback_linear_images);
|
||||
KYTY_CFG_SET(tessellation_enabled);
|
||||
KYTY_CFG_SET(vblank_frequency);
|
||||
KYTY_CFG_SET(console_language);
|
||||
KYTY_CFG_SET(vulkan_validation_enabled);
|
||||
@@ -210,6 +213,7 @@ public:
|
||||
}
|
||||
KYTY_CFG_GET(fullscreen_enabled);
|
||||
KYTY_CFG_GET(readback_linear_images);
|
||||
KYTY_CFG_GET(tessellation_enabled);
|
||||
vblank_frequency = s->value("vblank_frequency", vblank_frequency).toInt();
|
||||
console_language = s->value("console_language", console_language).toInt();
|
||||
if (console_language < 0 || console_language > MAX_CONSOLE_LANGUAGE) {
|
||||
|
||||
@@ -230,6 +230,7 @@ void ConfigurationEditDialog::Init(const Configuration& info) {
|
||||
: 0);
|
||||
m_ui->checkBox_fullscreen->setChecked(info.fullscreen_enabled);
|
||||
m_ui->checkBox_readback->setChecked(info.readback_linear_images);
|
||||
m_ui->checkBox_tessellation->setChecked(info.tessellation_enabled);
|
||||
m_ui->spinBox_vblank_frequency->setValue(info.vblank_frequency);
|
||||
m_ui->comboBox_console_language->clear();
|
||||
m_ui->comboBox_console_language->addItems(CONSOLE_LANGUAGE_NAMES);
|
||||
@@ -375,6 +376,7 @@ static void UpdateInfo(Configuration& info, Ui::ConfigurationEditDialog& ui) {
|
||||
info.gpu_index = ui.comboBox_gpu->currentIndex() - 1;
|
||||
info.fullscreen_enabled = ui.checkBox_fullscreen->isChecked();
|
||||
info.readback_linear_images = ui.checkBox_readback->isChecked();
|
||||
info.tessellation_enabled = ui.checkBox_tessellation->isChecked();
|
||||
info.vblank_frequency = ui.spinBox_vblank_frequency->value();
|
||||
info.console_language = ui.comboBox_console_language->currentIndex();
|
||||
info.vulkan_validation_enabled = ui.checkBox_vulkan_validation->isChecked();
|
||||
|
||||
@@ -226,6 +226,9 @@ static QStringList CreateEmulatorArgs(const Configuration& info) {
|
||||
args << "--fullscreen";
|
||||
}
|
||||
args << "--readback-linear-images" << BoolArg(info.readback_linear_images);
|
||||
if (info.tessellation_enabled) {
|
||||
args << "--tessellation";
|
||||
}
|
||||
args << "--vblank-frequency" << QString::number(info.vblank_frequency);
|
||||
args << "--console-language" << QString::number(info.console_language);
|
||||
args << "--vulkan-validation" << BoolArg(info.vulkan_validation_enabled);
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
PatchesDialog::PatchesDialog(const Configuration& game, QWidget* parent)
|
||||
: QDialog(parent), m_title_id(game.title_id.trimmed().toUpper()) {
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
setWindowTitle(tr("Cheats (Experimental) - %1").arg(game.name));
|
||||
setWindowTitle(tr("Cheats (experimental) - %1").arg(game.name));
|
||||
resize(640, 480);
|
||||
|
||||
auto* layout = new QVBoxLayout(this);
|
||||
|
||||
+36
-52
@@ -706,7 +706,7 @@ public:
|
||||
int Enable(uint32_t id) {
|
||||
std::scoped_lock lifecycle_lock(lifecycle_mutex);
|
||||
std::lock_guard state_lock(mutex);
|
||||
if (!stopped) {
|
||||
if (state == State::Playing) {
|
||||
return AVPLAYER_ERROR_OPERATION_FAILED;
|
||||
}
|
||||
if (fmt == nullptr || id >= fmt->nb_streams) {
|
||||
@@ -724,7 +724,7 @@ public:
|
||||
int Disable(uint32_t id) {
|
||||
std::scoped_lock lifecycle_lock(lifecycle_mutex);
|
||||
std::lock_guard state_lock(mutex);
|
||||
if (!stopped) {
|
||||
if (state == State::Playing) {
|
||||
return AVPLAYER_ERROR_OPERATION_FAILED;
|
||||
}
|
||||
if (video_id == static_cast<int>(id)) {
|
||||
@@ -755,9 +755,11 @@ public:
|
||||
return AVPLAYER_ERROR_OPERATION_FAILED;
|
||||
}
|
||||
time = CurrentTimeNoLock();
|
||||
restart = !stopped;
|
||||
restart = state == State::Playing;
|
||||
was_paused = paused;
|
||||
stopped = true;
|
||||
if (restart) {
|
||||
state = State::Ready;
|
||||
}
|
||||
}
|
||||
if (restart) {
|
||||
StopWorkers();
|
||||
@@ -778,7 +780,7 @@ public:
|
||||
int StartImpl(uint64_t ms, bool paused_after_start = false, bool show_seek_frame = false) {
|
||||
{
|
||||
std::lock_guard lock(mutex);
|
||||
stopped = true;
|
||||
state = State::Ready;
|
||||
}
|
||||
StopWorkers();
|
||||
interrupt_io = false;
|
||||
@@ -791,14 +793,17 @@ public:
|
||||
AutoEnable();
|
||||
}
|
||||
if (!video_id && !audio_id) {
|
||||
state = State::Stopped;
|
||||
return AVPLAYER_ERROR_OPERATION_FAILED;
|
||||
}
|
||||
if (!OpenCodecs()) {
|
||||
ResetNoLock(true);
|
||||
state = State::Stopped;
|
||||
return AVPLAYER_ERROR_OPERATION_FAILED;
|
||||
}
|
||||
if (!AllocateBuffers()) {
|
||||
ResetNoLock(true);
|
||||
state = State::Stopped;
|
||||
return AVPLAYER_ERROR_NO_MEMORY;
|
||||
}
|
||||
SeekNoLock(ms);
|
||||
@@ -809,12 +814,11 @@ public:
|
||||
pause_time = clock_start;
|
||||
seek_video_frame_pending =
|
||||
paused_after_start && show_seek_frame && video_id.has_value();
|
||||
stopped = false;
|
||||
}
|
||||
|
||||
if (!StartWorkers()) {
|
||||
std::lock_guard lock(mutex);
|
||||
stopped = true;
|
||||
state = State::Stopped;
|
||||
ResetNoLock(true);
|
||||
result = AVPLAYER_ERROR_OPERATION_FAILED;
|
||||
}
|
||||
@@ -825,20 +829,22 @@ public:
|
||||
}
|
||||
int Stop() {
|
||||
bool was_playing_video = false;
|
||||
AvPlayerEventReplacement stop_event;
|
||||
AvPlayerEventReplacement stop_event {};
|
||||
{
|
||||
std::scoped_lock lifecycle_lock(lifecycle_mutex);
|
||||
{
|
||||
std::lock_guard lock(mutex);
|
||||
was_playing_video = !stopped && video_id.has_value();
|
||||
stopped = true;
|
||||
if (state == State::Playing) {
|
||||
was_playing_video = video_id.has_value();
|
||||
stop_event = event;
|
||||
}
|
||||
state = State::Stopped;
|
||||
}
|
||||
StopWorkers();
|
||||
{
|
||||
std::lock_guard lock(mutex);
|
||||
ResetNoLock();
|
||||
}
|
||||
stop_event = TakeStopEvent();
|
||||
}
|
||||
if (was_playing_video) {
|
||||
::printf("AvPlayer video stopped\n");
|
||||
@@ -872,7 +878,8 @@ public:
|
||||
}
|
||||
bool Active() const {
|
||||
std::lock_guard lock(mutex);
|
||||
return !stopped && !pipeline_failed && !DrainedNoLock();
|
||||
return state == State::Ready ||
|
||||
(state == State::Playing && !pipeline_failed && !DrainedNoLock());
|
||||
}
|
||||
uint64_t CurrentTime() const {
|
||||
std::lock_guard lock(mutex);
|
||||
@@ -888,7 +895,7 @@ public:
|
||||
return StartImpl(ms, was_paused, true);
|
||||
}
|
||||
uint64_t CurrentTimeNoLock() const {
|
||||
if (stopped) {
|
||||
if (state != State::Playing) {
|
||||
return 0;
|
||||
}
|
||||
using namespace std::chrono;
|
||||
@@ -925,7 +932,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
std::lock_guard lock(mutex);
|
||||
if (stopped || !video_id) {
|
||||
if (state != State::Playing || !video_id) {
|
||||
return false;
|
||||
}
|
||||
const bool deliver_seek_frame = paused && seek_video_frame_pending;
|
||||
@@ -955,7 +962,6 @@ public:
|
||||
current_video = std::move(*frame);
|
||||
*out = current_video->info;
|
||||
RecordLoopBoundary(*current_video);
|
||||
completion_changed.notify_all();
|
||||
if (deliver_seek_frame) {
|
||||
seek_video_frame_pending = false;
|
||||
}
|
||||
@@ -966,7 +972,8 @@ public:
|
||||
return false;
|
||||
}
|
||||
std::lock_guard lock(mutex);
|
||||
if (paused || stopped || !audio_id || trick_speed != AVPLAYER_TRICK_SPEED_NORMAL) {
|
||||
if (paused || state != State::Playing || !audio_id ||
|
||||
trick_speed != AVPLAYER_TRICK_SPEED_NORMAL) {
|
||||
return false;
|
||||
}
|
||||
auto frame = audio_frames.TryPop();
|
||||
@@ -987,7 +994,6 @@ public:
|
||||
current_audio->info.details.audio.language_code, 4);
|
||||
last_audio_ts = out->time_stamp;
|
||||
RecordLoopBoundary(*current_audio);
|
||||
completion_changed.notify_all();
|
||||
return true;
|
||||
}
|
||||
std::optional<int32_t> TakeWarning() {
|
||||
@@ -1000,13 +1006,12 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
enum class State { Ready, Playing, Stopped };
|
||||
|
||||
bool DrainedNoLock() const {
|
||||
return demux_eof && video_done && audio_done && video_frames.Empty() &&
|
||||
audio_frames.Empty();
|
||||
}
|
||||
AvPlayerEventReplacement TakeStopEvent() {
|
||||
return stop_event_sent.exchange(true) ? AvPlayerEventReplacement {} : event;
|
||||
}
|
||||
void RecordLoopBoundary(const ReadyFrame& frame) {
|
||||
if (frame.timestamp_offset > last_output_loop_offset) {
|
||||
last_output_loop_offset = frame.timestamp_offset;
|
||||
@@ -1198,11 +1203,10 @@ private:
|
||||
StopWorkers();
|
||||
return false;
|
||||
}
|
||||
stop_event_sent = false;
|
||||
state = State::Playing;
|
||||
return true;
|
||||
}
|
||||
void NotifyWorkers() {
|
||||
completion_changed.notify_all();
|
||||
video_packets.Notify();
|
||||
audio_packets.Notify();
|
||||
video_buffers.Notify();
|
||||
@@ -1289,13 +1293,6 @@ private:
|
||||
demux_eof = true;
|
||||
video_packets.Notify();
|
||||
audio_packets.Notify();
|
||||
std::unique_lock lock(mutex);
|
||||
completion_changed.wait(lock, [&] { return worker_stop || DrainedNoLock(); });
|
||||
if (!worker_stop) {
|
||||
const auto stop_event = TakeStopEvent();
|
||||
lock.unlock();
|
||||
emit_event(stop_event, AVPLAYER_EVENT_STATE_STOP);
|
||||
}
|
||||
}
|
||||
void VideoDecoder() {
|
||||
Decoder(video_packets, video_ctx, video_buffers, video_frames, video_done,
|
||||
@@ -1343,11 +1340,7 @@ private:
|
||||
break;
|
||||
}
|
||||
}
|
||||
{
|
||||
std::lock_guard lock(mutex);
|
||||
done = true;
|
||||
}
|
||||
completion_changed.notify_all();
|
||||
done = true;
|
||||
}
|
||||
bool DecodePacket(AVCodecContext* codec, AVPacket* packet, uint64_t timestamp_offset,
|
||||
WorkQueue<std::unique_ptr<GuestBuffer>>& buffers,
|
||||
@@ -1412,15 +1405,8 @@ private:
|
||||
return use_vdec2 ? static_cast<uint32_t>(s->codecpar->height)
|
||||
: align_up(static_cast<uint32_t>(s->codecpar->height), 16);
|
||||
}
|
||||
float Aspect(AVStream* s) const {
|
||||
if (s->codecpar->height == 0) {
|
||||
return 0.0f;
|
||||
}
|
||||
double r = static_cast<double>(s->codecpar->width) / s->codecpar->height;
|
||||
if (s->sample_aspect_ratio.num > 0 && s->sample_aspect_ratio.den > 0) {
|
||||
r *= av_q2d(s->sample_aspect_ratio);
|
||||
}
|
||||
return static_cast<float>(r);
|
||||
float Aspect(AVRational ratio) const {
|
||||
return ratio.num > 0 && ratio.den > 0 ? static_cast<float>(av_q2d(ratio)) : 0.0f;
|
||||
}
|
||||
uint64_t Duration(AVStream* s) const {
|
||||
return s->duration != AV_NOPTS_VALUE
|
||||
@@ -1433,14 +1419,14 @@ private:
|
||||
std::memset(v, 0, sizeof(*v));
|
||||
v->width = Width(s);
|
||||
v->height = Height(s);
|
||||
v->aspect_ratio = Aspect(s);
|
||||
v->aspect_ratio = Aspect(s->sample_aspect_ratio);
|
||||
lang(v->language_code, s->metadata);
|
||||
}
|
||||
void FillVideoEx(AVStream* s, AvPlayerVideoEx* v) const {
|
||||
void FillVideoEx(AVStream* s, AvPlayerVideoEx* v, AVRational aspect) const {
|
||||
std::memset(v, 0, sizeof(*v));
|
||||
v->width = Width(s);
|
||||
v->height = Height(s);
|
||||
v->aspect_ratio = Aspect(s);
|
||||
v->aspect_ratio = Aspect(aspect);
|
||||
v->pitch = VideoPitch(s);
|
||||
v->luma_bit_depth = 8;
|
||||
v->chroma_bit_depth = 8;
|
||||
@@ -1476,7 +1462,7 @@ private:
|
||||
FillVideo(s, &d->video);
|
||||
}
|
||||
if (ex) {
|
||||
FillVideoEx(s, &ex->video);
|
||||
FillVideoEx(s, &ex->video, s->sample_aspect_ratio);
|
||||
}
|
||||
break;
|
||||
case AVMEDIA_TYPE_AUDIO:
|
||||
@@ -1561,7 +1547,7 @@ private:
|
||||
info->time_stamp = to_ms(
|
||||
src->best_effort_timestamp != AV_NOPTS_VALUE ? src->best_effort_timestamp : src->pts,
|
||||
s->time_base);
|
||||
FillVideoEx(s, &info->details.video);
|
||||
FillVideoEx(s, &info->details.video, src->sample_aspect_ratio);
|
||||
info->details.video.crop_left_offset = static_cast<uint32_t>(src->crop_left);
|
||||
info->details.video.crop_right_offset =
|
||||
static_cast<uint32_t>(src->crop_right + (pitch - src->width));
|
||||
@@ -1672,11 +1658,9 @@ private:
|
||||
std::atomic_bool demux_eof {true};
|
||||
std::atomic_bool video_done {true};
|
||||
std::atomic_bool audio_done {true};
|
||||
std::atomic_bool stop_event_sent {true};
|
||||
std::condition_variable completion_changed;
|
||||
std::mutex lifecycle_mutex;
|
||||
mutable std::mutex mutex;
|
||||
bool stopped = true;
|
||||
State state = State::Ready;
|
||||
bool paused = false;
|
||||
bool seek_video_frame_pending = false;
|
||||
std::atomic_bool loop {false};
|
||||
@@ -2029,7 +2013,7 @@ Bool KYTY_SYSV_ABI AvPlayerGetAudioData(AvPlayerInternal* h, AvPlayerFrameInfo*
|
||||
}
|
||||
Bool KYTY_SYSV_ABI AvPlayerIsActive(AvPlayerInternal* h) {
|
||||
PRINT_NAME();
|
||||
return h != nullptr && h->source != nullptr && h->source->Active() ? 1 : 0;
|
||||
return h != nullptr && (h->source == nullptr || h->source->Active());
|
||||
}
|
||||
uint64_t KYTY_SYSV_ABI AvPlayerCurrentTime(AvPlayerInternal* h) {
|
||||
PRINT_NAME();
|
||||
|
||||
@@ -64,6 +64,7 @@ static void PrintUsage() {
|
||||
::printf(" --gpu-assisted-validation <t|f> Bounds-check shader accesses on the GPU.\n"
|
||||
" Implies --vulkan-validation; very slow.\n");
|
||||
::printf(" --shader-validation <true|false> Enable shader validation.\n");
|
||||
::printf(" --tessellation Draw tessellation patches; skipped by default.\n");
|
||||
::printf(" --shader-optimization-type <value> None, Size, or Performance.\n");
|
||||
::printf(" --shader-log-direction <value> Silent, Console, or File.\n");
|
||||
::printf(" --shader-log-folder <path> Shader log output folder.\n");
|
||||
@@ -180,6 +181,11 @@ static bool ParseArgs(int argc, char* argv[], RunOptions& options, bool& show_he
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg == "--tessellation") {
|
||||
options.config.tessellation_enabled = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg == "--profile") {
|
||||
options.config.profiler_enabled = true;
|
||||
continue;
|
||||
|
||||
@@ -1246,7 +1246,7 @@ ResourcePlan ConditionalSamplerPlan(bool diamond, bool reverse, bool reverse_phi
|
||||
flag = fixture.Emit(ValueOpcode::LaneId);
|
||||
}
|
||||
fixture.program.block_info[0].condition =
|
||||
fixture.Emit(ValueOpcode::IEqual32, {flag, Value(0u)});
|
||||
fixture.Emit(ValueOpcode::SGreaterThanEqual32, {flag, Value(0u)});
|
||||
if (writable) {
|
||||
MemoryInfo memory;
|
||||
memory.kind = ResourceKind::Buffer;
|
||||
@@ -1324,9 +1324,10 @@ void TestConditionalSamplerPhi() {
|
||||
.userdata = &memory,
|
||||
.read_specialization_memory =
|
||||
ReadLinearTestMemory};
|
||||
for (uint32_t flag = 0; flag < 2; ++flag) {
|
||||
memory.words[(0x1000 + 196) / 4] = flag;
|
||||
const uint32_t first = (flag != 0u) != reverse ? 480 / 4 : 448 / 4;
|
||||
// Sampler selection compares a signed value against zero.
|
||||
for (const auto flag : {-1, 0, 1, INT32_MIN, INT32_MAX}) {
|
||||
memory.words[(0x1000 + 196) / 4] = std::bit_cast<uint32_t>(flag);
|
||||
const uint32_t first = (flag < 0) != reverse ? 480 / 4 : 448 / 4;
|
||||
memory.fail_address = 0x1000 + (first == 448 / 4 ? 480u : 448u);
|
||||
DescriptorValue selected;
|
||||
Check(EvaluateDescriptorSource(plan, source, runtime, selected),
|
||||
|
||||
@@ -12831,6 +12831,7 @@ public:
|
||||
const uint32_t extent = depth_feedback ? 8 : 32;
|
||||
constexpr uintptr_t depth_address = 0x0000000204400000ull;
|
||||
constexpr uint64_t allocation_size = 0x40000;
|
||||
constexpr uint64_t rect_address = depth_address + 0x8000;
|
||||
EnsureRuntimeContext();
|
||||
RenderContext context(m_runtime_context);
|
||||
auto &scheduler = context.GetCommandScheduler();
|
||||
@@ -12865,6 +12866,15 @@ public:
|
||||
static_cast<float *>(mapped)[y * 64 + x] = initial_depth(x, y);
|
||||
}
|
||||
}
|
||||
if (!depth_feedback && !packed_vertex_color) {
|
||||
// Rectangle input contains three position/UV records.
|
||||
constexpr std::array<float, 24> rect_vertices{
|
||||
-0.75f, -0.75f, 0, 0, 0, 0, 0, 0,
|
||||
0.75f, -0.75f, 0, 0, 1, 0, 0, 0,
|
||||
-0.75f, 0.75f, 0, 0, 0, 1, 0, 0};
|
||||
std::memcpy(reinterpret_cast<void *>(rect_address), rect_vertices.data(),
|
||||
sizeof(rect_vertices));
|
||||
}
|
||||
resources.MapMemory(depth_address, allocation_size);
|
||||
if (depth_feedback) {
|
||||
depth.desc.type = BindingType::DepthTarget;
|
||||
@@ -13521,6 +13531,82 @@ public:
|
||||
Require(name, "sparse MRT3 output", sparse_pixels[component] == expected,
|
||||
"MRT3 was compacted to a different slot or clipped by unused MRT0");
|
||||
}
|
||||
|
||||
// A fourth VS invocation reads beyond the descriptor instead of reconstructing the corner.
|
||||
const ShaderBufferResource rect_buffer{{
|
||||
static_cast<u32>(rect_address),
|
||||
static_cast<u32>(rect_address >> 32u) | (32u << 16u), 3,
|
||||
DstSel(4, 5, 6, 7) |
|
||||
(static_cast<u32>(Prospero::BufferFormat::k32Float) << 12u)}};
|
||||
static const auto rect_vertex_code = [] {
|
||||
std::vector<u32> code{
|
||||
EncodeMubuf0(0x0d, 0, true, false), EncodeMubuf1(0, 2, 5),
|
||||
EncodeMubuf0(0x0d, 16, true, false), EncodeMubuf1(2, 2, 5)};
|
||||
AppendVMovU32(&code, 4, 0);
|
||||
AppendVMovLiteral(&code, 6, 0x3f800000u);
|
||||
code.insert(code.end(), {EncodeExp0(0x0c, 0xf), EncodeExp1(0, 1, 4, 6),
|
||||
EncodeExp0(0x20, 0xf), EncodeExp1(2, 3, 4, 6)});
|
||||
AppendEnd(&code);
|
||||
return code;
|
||||
}();
|
||||
static const auto rect_pixel_code = [] {
|
||||
std::vector<u32> code;
|
||||
for (u32 component = 0; component < 2; component++) {
|
||||
code.push_back(EncodeVintrp(0, 20 + component, 0, component, 0));
|
||||
code.push_back(EncodeVintrp(1, 20 + component, 0, component, 1));
|
||||
}
|
||||
AppendVMovU32(&code, 22, 0);
|
||||
AppendVMovLiteral(&code, 23, 0x3f800000u);
|
||||
code.insert(code.end(), {EncodeExp0(0x03, 0xf), EncodeExp1(20, 21, 22, 23)});
|
||||
AppendEnd(&code);
|
||||
return code;
|
||||
}();
|
||||
const auto rect_vs = reinterpret_cast<uint64_t>(rect_vertex_code.data());
|
||||
const auto rect_ps = reinterpret_cast<uint64_t>(rect_pixel_code.data());
|
||||
ShaderMapUserData(rect_vs,
|
||||
{.type = Prospero::ShaderBinaryType::kGs, .user_data = &native_user_data,
|
||||
.code_size_bytes = static_cast<u32>(rect_vertex_code.size() * sizeof(u32))});
|
||||
ShaderMapUserData(rect_ps,
|
||||
{.type = Prospero::ShaderBinaryType::kPs,
|
||||
.code_size_bytes = static_cast<u32>(rect_pixel_code.size() * sizeof(u32))});
|
||||
shaders.SetEsShaderBase(rect_vs);
|
||||
shaders.SetPsShaderBase(rect_ps);
|
||||
shaders.SetGsShaderResource2({.user_sgpr = 4});
|
||||
for (u32 i = 0; i < 4; i++) {
|
||||
shaders.SetGsUserSgpr(i, rect_buffer.fields[i], HW::UserSgprType::Vsharp);
|
||||
}
|
||||
registers.SetPsInControl(0x8001);
|
||||
registers.SetPsInputEna(2);
|
||||
registers.SetPsInputAddr(2);
|
||||
registers.SetPsInputSettings(0, 0);
|
||||
for (const auto primitive : {Prospero::PrimitiveType::kRectList,
|
||||
Prospero::PrimitiveType::kRectListLegacy}) {
|
||||
const char *rect_name = primitive == Prospero::PrimitiveType::kRectList
|
||||
? "RectListThreeRecords" : "LegacyRectListThreeRecords";
|
||||
user_config.SetPrimitiveType(primitive);
|
||||
registers.SetModeControl({});
|
||||
TextureCacheTestAccess::ClearImage(cache, scheduler.Current(), sparse_color.image_id,
|
||||
{vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}, {});
|
||||
RenderExecutorTestAccess::DrawAuto(
|
||||
executor, scheduler.Current(), {.vertex_count = 3, .instance_count = 1});
|
||||
const auto pixels = ReadCachedTexel(name, context, sparse_color.image_id,
|
||||
{}, {extent, extent, 1});
|
||||
for (u32 y = 0; y < extent; y++) {
|
||||
for (u32 x = 0; x < extent; x++) {
|
||||
const bool inside = x >= 4 && x < 28 && y >= 4 && y < 28;
|
||||
const auto offset = 4 * (y * extent + x);
|
||||
const std::array<float, 4> expected{
|
||||
inside ? (x + 0.5f - 4) / 24 : 0,
|
||||
inside ? (y + 0.5f - 4) / 24 : 0, 0, inside ? 1.0f : 0};
|
||||
for (u32 component = 0; component < 4; component++) {
|
||||
Require(rect_name, "three-vertex rectangle coverage and UV",
|
||||
std::abs(std::bit_cast<float>(pixels[offset + component]) -
|
||||
expected[component]) < 0.0001f,
|
||||
"rectangle reconstruction lost its fourth corner or interpolated UVs");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DestroyBuffer(&stencil_readback);
|
||||
|
||||
vertex_shader = owned_vertex_shader;
|
||||
@@ -15011,6 +15097,7 @@ private:
|
||||
Require("VulkanHarness", "graphics", available_features12.shaderOutputLayer == true,
|
||||
"vertex layer output is not supported");
|
||||
Require("VulkanHarness", "graphics", available_features.fillModeNonSolid &&
|
||||
available_features.tessellationShader &&
|
||||
available_depth_clip.depthClipEnable && available_clip_control.depthClipControl &&
|
||||
available_color_write.colorWriteEnable &&
|
||||
available_feedback_layout.attachmentFeedbackLoopLayout &&
|
||||
@@ -15076,6 +15163,7 @@ private:
|
||||
device_features.sampleRateShading = true;
|
||||
device_features.shaderInt64 = true;
|
||||
device_features.fillModeNonSolid = true;
|
||||
device_features.tessellationShader = true;
|
||||
device_info.pEnabledFeatures = &device_features;
|
||||
constexpr const char *device_extensions[] = {
|
||||
VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME,
|
||||
|
||||
Reference in New Issue
Block a user