Skeleton xenia::gpu::vulkan implementation, enough to start trace viewer.
This commit is contained in:
parent
ca5902c111
commit
05107d2d3e
|
@ -183,6 +183,7 @@ solution("xenia")
|
||||||
include("src/xenia/debug/ui")
|
include("src/xenia/debug/ui")
|
||||||
include("src/xenia/gpu")
|
include("src/xenia/gpu")
|
||||||
include("src/xenia/gpu/gl4")
|
include("src/xenia/gpu/gl4")
|
||||||
|
include("src/xenia/gpu/vulkan")
|
||||||
include("src/xenia/hid")
|
include("src/xenia/hid")
|
||||||
include("src/xenia/hid/nop")
|
include("src/xenia/hid/nop")
|
||||||
include("src/xenia/kernel")
|
include("src/xenia/kernel")
|
||||||
|
|
|
@ -1023,6 +1023,14 @@ void Value::VectorSub(Value* other, TypeName type, bool is_unsigned,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case FLOAT32_TYPE:
|
||||||
|
assert_false(is_unsigned);
|
||||||
|
assert_false(saturate);
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
constant.v128.f32[i] -= other->constant.v128.f32[i];
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert_unhandled_case(type);
|
assert_unhandled_case(type);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1439,7 +1439,8 @@ void TraceViewer::DrawStateUI() {
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
}
|
}
|
||||||
if (ImGui::CollapsingHeader("Vertex Shader Output")) {
|
if (ImGui::CollapsingHeader("Vertex Shader Output") &&
|
||||||
|
QueryVSOutputElementSize()) {
|
||||||
auto size = QueryVSOutputSize();
|
auto size = QueryVSOutputSize();
|
||||||
auto el_size = QueryVSOutputElementSize();
|
auto el_size = QueryVSOutputElementSize();
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
|
|
|
@ -54,9 +54,9 @@ class TraceViewer {
|
||||||
virtual uintptr_t GetTextureEntry(const TextureInfo& texture_info,
|
virtual uintptr_t GetTextureEntry(const TextureInfo& texture_info,
|
||||||
const SamplerInfo& sampler_info) = 0;
|
const SamplerInfo& sampler_info) = 0;
|
||||||
|
|
||||||
virtual size_t QueryVSOutputSize() = 0;
|
virtual size_t QueryVSOutputSize() { return 0; }
|
||||||
virtual size_t QueryVSOutputElementSize() = 0;
|
virtual size_t QueryVSOutputElementSize() { return 0; }
|
||||||
virtual bool QueryVSOutput(void* buffer, size_t size) = 0;
|
virtual bool QueryVSOutput(void* buffer, size_t size) { return false; }
|
||||||
|
|
||||||
virtual bool Setup();
|
virtual bool Setup();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
project_root = "../../../.."
|
||||||
|
include(project_root.."/tools/build")
|
||||||
|
|
||||||
|
group("src")
|
||||||
|
project("xenia-gpu-vulkan")
|
||||||
|
uuid("717590b4-f579-4162-8f23-0624e87d6cca")
|
||||||
|
kind("StaticLib")
|
||||||
|
language("C++")
|
||||||
|
links({
|
||||||
|
"vulkan-loader",
|
||||||
|
"xenia-base",
|
||||||
|
"xenia-gpu",
|
||||||
|
"xenia-ui",
|
||||||
|
"xenia-ui-spirv",
|
||||||
|
"xenia-ui-vulkan",
|
||||||
|
"xxhash",
|
||||||
|
})
|
||||||
|
defines({
|
||||||
|
})
|
||||||
|
includedirs({
|
||||||
|
project_root.."/third_party/gflags/src",
|
||||||
|
})
|
||||||
|
local_platform_files()
|
||||||
|
|
||||||
|
-- TODO(benvanik): kill this and move to the debugger UI.
|
||||||
|
group("src")
|
||||||
|
project("xenia-gpu-vulkan-trace-viewer")
|
||||||
|
uuid("86a1dddc-a26a-4885-8c55-cf745225d93e")
|
||||||
|
kind("WindowedApp")
|
||||||
|
language("C++")
|
||||||
|
links({
|
||||||
|
"gflags",
|
||||||
|
"imgui",
|
||||||
|
"vulkan-loader",
|
||||||
|
"xenia-apu",
|
||||||
|
"xenia-apu-nop",
|
||||||
|
"xenia-apu-xaudio2",
|
||||||
|
"xenia-base",
|
||||||
|
"xenia-core",
|
||||||
|
"xenia-cpu",
|
||||||
|
"xenia-cpu-backend-x64",
|
||||||
|
"xenia-gpu",
|
||||||
|
"xenia-gpu-vulkan",
|
||||||
|
"xenia-hid-nop",
|
||||||
|
"xenia-hid-winkey",
|
||||||
|
"xenia-hid-xinput",
|
||||||
|
"xenia-kernel",
|
||||||
|
"xenia-ui",
|
||||||
|
"xenia-ui-spirv",
|
||||||
|
"xenia-ui-vulkan",
|
||||||
|
"xenia-vfs",
|
||||||
|
})
|
||||||
|
flags({
|
||||||
|
"WinMain", -- Use WinMain instead of main.
|
||||||
|
})
|
||||||
|
defines({
|
||||||
|
})
|
||||||
|
includedirs({
|
||||||
|
project_root.."/third_party/gflags/src",
|
||||||
|
})
|
||||||
|
files({
|
||||||
|
"vulkan_trace_viewer_main.cc",
|
||||||
|
"../../base/main_"..platform_suffix..".cc",
|
||||||
|
})
|
||||||
|
|
||||||
|
filter("platforms:Windows")
|
||||||
|
-- Only create the .user file if it doesn't already exist.
|
||||||
|
local user_file = project_root.."/build/xenia-gpu-vulkan-trace-viewer.vcxproj.user"
|
||||||
|
if not os.isfile(user_file) then
|
||||||
|
debugdir(project_root)
|
||||||
|
debugargs({
|
||||||
|
"--flagfile=scratch/flags.txt",
|
||||||
|
"2>&1",
|
||||||
|
"1>scratch/stdout-trace-viewer.txt",
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
group("src")
|
||||||
|
project("xenia-gpu-vulkan-trace-dump")
|
||||||
|
uuid("0dd0dd1c-b321-494d-ab9a-6c062f0c65cc")
|
||||||
|
kind("ConsoleApp")
|
||||||
|
language("C++")
|
||||||
|
links({
|
||||||
|
"gflags",
|
||||||
|
"imgui",
|
||||||
|
"vulkan-loader",
|
||||||
|
"xenia-apu",
|
||||||
|
"xenia-apu-nop",
|
||||||
|
"xenia-apu-xaudio2",
|
||||||
|
"xenia-base",
|
||||||
|
"xenia-core",
|
||||||
|
"xenia-cpu",
|
||||||
|
"xenia-cpu-backend-x64",
|
||||||
|
"xenia-gpu",
|
||||||
|
"xenia-gpu-vulkan",
|
||||||
|
"xenia-hid-nop",
|
||||||
|
"xenia-hid-winkey",
|
||||||
|
"xenia-hid-xinput",
|
||||||
|
"xenia-kernel",
|
||||||
|
"xenia-ui",
|
||||||
|
"xenia-ui-spirv",
|
||||||
|
"xenia-ui-vulkan",
|
||||||
|
"xenia-vfs",
|
||||||
|
})
|
||||||
|
defines({
|
||||||
|
})
|
||||||
|
includedirs({
|
||||||
|
project_root.."/third_party/gflags/src",
|
||||||
|
})
|
||||||
|
files({
|
||||||
|
"vulkan_trace_dump_main.cc",
|
||||||
|
"../../base/main_"..platform_suffix..".cc",
|
||||||
|
})
|
||||||
|
|
||||||
|
filter("platforms:Windows")
|
||||||
|
-- Only create the .user file if it doesn't already exist.
|
||||||
|
local user_file = project_root.."/build/xenia-gpu-vulkan-trace-dump.vcxproj.user"
|
||||||
|
if not os.isfile(user_file) then
|
||||||
|
debugdir(project_root)
|
||||||
|
debugargs({
|
||||||
|
"--flagfile=scratch/flags.txt",
|
||||||
|
"2>&1",
|
||||||
|
"1>scratch/stdout-trace-dump.txt",
|
||||||
|
})
|
||||||
|
end
|
|
@ -0,0 +1,585 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2016 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xenia/gpu/vulkan/vulkan_command_processor.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "xenia/base/logging.h"
|
||||||
|
#include "xenia/base/math.h"
|
||||||
|
#include "xenia/base/profiling.h"
|
||||||
|
#include "xenia/gpu/gpu_flags.h"
|
||||||
|
#include "xenia/gpu/sampler_info.h"
|
||||||
|
#include "xenia/gpu/texture_info.h"
|
||||||
|
#include "xenia/gpu/vulkan/vulkan_gpu_flags.h"
|
||||||
|
#include "xenia/gpu/vulkan/vulkan_graphics_system.h"
|
||||||
|
#include "xenia/gpu/xenos.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace gpu {
|
||||||
|
namespace vulkan {
|
||||||
|
|
||||||
|
using namespace xe::gpu::xenos;
|
||||||
|
|
||||||
|
VulkanCommandProcessor::VulkanCommandProcessor(
|
||||||
|
VulkanGraphicsSystem* graphics_system, kernel::KernelState* kernel_state)
|
||||||
|
: CommandProcessor(graphics_system, kernel_state) {}
|
||||||
|
|
||||||
|
VulkanCommandProcessor::~VulkanCommandProcessor() = default;
|
||||||
|
|
||||||
|
void VulkanCommandProcessor::ClearCaches() { CommandProcessor::ClearCaches(); }
|
||||||
|
|
||||||
|
bool VulkanCommandProcessor::SetupContext() {
|
||||||
|
if (!CommandProcessor::SetupContext()) {
|
||||||
|
XELOGE("Unable to initialize base command processor context");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanCommandProcessor::ShutdownContext() {
|
||||||
|
CommandProcessor::ShutdownContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanCommandProcessor::MakeCoherent() {
|
||||||
|
RegisterFile* regs = register_file_;
|
||||||
|
auto status_host = regs->values[XE_GPU_REG_COHER_STATUS_HOST].u32;
|
||||||
|
|
||||||
|
CommandProcessor::MakeCoherent();
|
||||||
|
|
||||||
|
if (status_host & 0x80000000ul) {
|
||||||
|
// scratch_buffer_.ClearCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanCommandProcessor::PrepareForWait() {
|
||||||
|
SCOPE_profile_cpu_f("gpu");
|
||||||
|
|
||||||
|
CommandProcessor::PrepareForWait();
|
||||||
|
|
||||||
|
// TODO(benvanik): fences and fancy stuff. We should figure out a way to
|
||||||
|
// make interrupt callbacks from the GPU so that we don't have to do a full
|
||||||
|
// synchronize here.
|
||||||
|
// glFlush();
|
||||||
|
// glFinish();
|
||||||
|
|
||||||
|
context_->ClearCurrent();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanCommandProcessor::ReturnFromWait() {
|
||||||
|
context_->MakeCurrent();
|
||||||
|
|
||||||
|
CommandProcessor::ReturnFromWait();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanCommandProcessor::PerformSwap(uint32_t frontbuffer_ptr,
|
||||||
|
uint32_t frontbuffer_width,
|
||||||
|
uint32_t frontbuffer_height) {
|
||||||
|
// Ensure we issue any pending draws.
|
||||||
|
// draw_batcher_.Flush(DrawBatcher::FlushMode::kMakeCoherent);
|
||||||
|
|
||||||
|
// Need to finish to be sure the other context sees the right data.
|
||||||
|
// TODO(benvanik): prevent this? fences?
|
||||||
|
// glFinish();
|
||||||
|
|
||||||
|
if (context_->WasLost()) {
|
||||||
|
// We've lost the context due to a TDR.
|
||||||
|
// TODO: Dump the current commands to a tracefile.
|
||||||
|
assert_always();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove any dead textures, etc.
|
||||||
|
// texture_cache_.Scavenge();
|
||||||
|
}
|
||||||
|
|
||||||
|
Shader* VulkanCommandProcessor::LoadShader(ShaderType shader_type,
|
||||||
|
uint32_t guest_address,
|
||||||
|
const uint32_t* host_address,
|
||||||
|
uint32_t dword_count) {
|
||||||
|
// return shader_cache_.LookupOrInsertShader(shader_type, host_address,
|
||||||
|
// dword_count);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VulkanCommandProcessor::IssueDraw(PrimitiveType prim_type,
|
||||||
|
uint32_t index_count,
|
||||||
|
IndexBufferInfo* index_buffer_info) {
|
||||||
|
#if FINE_GRAINED_DRAW_SCOPES
|
||||||
|
SCOPE_profile_cpu_f("gpu");
|
||||||
|
#endif // FINE_GRAINED_DRAW_SCOPES
|
||||||
|
|
||||||
|
// Skip all drawing for now - what did you expect? :)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
bool draw_valid = false;
|
||||||
|
// if (index_buffer_info) {
|
||||||
|
// draw_valid = draw_batcher_.BeginDrawElements(prim_type, index_count,
|
||||||
|
// index_buffer_info->format);
|
||||||
|
//} else {
|
||||||
|
// draw_valid = draw_batcher_.BeginDrawArrays(prim_type, index_count);
|
||||||
|
//}
|
||||||
|
if (!draw_valid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& regs = *register_file_;
|
||||||
|
|
||||||
|
auto enable_mode =
|
||||||
|
static_cast<ModeControl>(regs[XE_GPU_REG_RB_MODECONTROL].u32 & 0x7);
|
||||||
|
if (enable_mode == ModeControl::kIgnore) {
|
||||||
|
// Ignored.
|
||||||
|
// draw_batcher_.DiscardDraw();
|
||||||
|
return true;
|
||||||
|
} else if (enable_mode == ModeControl::kCopy) {
|
||||||
|
// Special copy handling.
|
||||||
|
// draw_batcher_.DiscardDraw();
|
||||||
|
return IssueCopy();
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CHECK_ISSUE_UPDATE_STATUS(status, mismatch, error_message) \
|
||||||
|
{ \
|
||||||
|
if (status == UpdateStatus::kError) { \
|
||||||
|
XELOGE(error_message); \
|
||||||
|
/*draw_batcher_.DiscardDraw(); */ \
|
||||||
|
return false; \
|
||||||
|
} else if (status == UpdateStatus::kMismatch) { \
|
||||||
|
mismatch = true; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateStatus status;
|
||||||
|
bool mismatch = false;
|
||||||
|
status = UpdateShaders(prim_type);
|
||||||
|
CHECK_ISSUE_UPDATE_STATUS(status, mismatch, "Unable to prepare draw shaders");
|
||||||
|
status = UpdateRenderTargets();
|
||||||
|
CHECK_ISSUE_UPDATE_STATUS(status, mismatch, "Unable to setup render targets");
|
||||||
|
// if (!active_framebuffer_) {
|
||||||
|
// // No framebuffer, so nothing we do will actually have an effect.
|
||||||
|
// // Treat it as a no-op.
|
||||||
|
// // TODO(benvanik): if we have a vs export, still allow it to go.
|
||||||
|
// draw_batcher_.DiscardDraw();
|
||||||
|
// return true;
|
||||||
|
//}
|
||||||
|
|
||||||
|
status = UpdateState(prim_type);
|
||||||
|
CHECK_ISSUE_UPDATE_STATUS(status, mismatch, "Unable to setup render state");
|
||||||
|
status = PopulateSamplers();
|
||||||
|
CHECK_ISSUE_UPDATE_STATUS(status, mismatch,
|
||||||
|
"Unable to prepare draw samplers");
|
||||||
|
|
||||||
|
status = PopulateIndexBuffer(index_buffer_info);
|
||||||
|
CHECK_ISSUE_UPDATE_STATUS(status, mismatch, "Unable to setup index buffer");
|
||||||
|
status = PopulateVertexBuffers();
|
||||||
|
CHECK_ISSUE_UPDATE_STATUS(status, mismatch, "Unable to setup vertex buffers");
|
||||||
|
|
||||||
|
// if (!draw_batcher_.CommitDraw()) {
|
||||||
|
// return false;
|
||||||
|
//}
|
||||||
|
|
||||||
|
// draw_batcher_.Flush(DrawBatcher::FlushMode::kMakeCoherent);
|
||||||
|
if (context_->WasLost()) {
|
||||||
|
// This draw lost us the context. This typically isn't hit.
|
||||||
|
assert_always();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VulkanCommandProcessor::SetShadowRegister(uint32_t* dest,
|
||||||
|
uint32_t register_name) {
|
||||||
|
uint32_t value = register_file_->values[register_name].u32;
|
||||||
|
if (*dest == value) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*dest = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VulkanCommandProcessor::SetShadowRegister(float* dest,
|
||||||
|
uint32_t register_name) {
|
||||||
|
float value = register_file_->values[register_name].f32;
|
||||||
|
if (*dest == value) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*dest = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanCommandProcessor::UpdateStatus VulkanCommandProcessor::UpdateShaders(
|
||||||
|
PrimitiveType prim_type) {
|
||||||
|
auto& regs = update_shaders_regs_;
|
||||||
|
|
||||||
|
// These are the constant base addresses/ranges for shaders.
|
||||||
|
// We have these hardcoded right now cause nothing seems to differ.
|
||||||
|
assert_true(register_file_->values[XE_GPU_REG_SQ_VS_CONST].u32 ==
|
||||||
|
0x000FF000 ||
|
||||||
|
register_file_->values[XE_GPU_REG_SQ_VS_CONST].u32 == 0x00000000);
|
||||||
|
assert_true(register_file_->values[XE_GPU_REG_SQ_PS_CONST].u32 ==
|
||||||
|
0x000FF100 ||
|
||||||
|
register_file_->values[XE_GPU_REG_SQ_PS_CONST].u32 == 0x00000000);
|
||||||
|
|
||||||
|
bool dirty = false;
|
||||||
|
dirty |= SetShadowRegister(®s.pa_su_sc_mode_cntl,
|
||||||
|
XE_GPU_REG_PA_SU_SC_MODE_CNTL);
|
||||||
|
dirty |= SetShadowRegister(®s.sq_program_cntl, XE_GPU_REG_SQ_PROGRAM_CNTL);
|
||||||
|
dirty |= SetShadowRegister(®s.sq_context_misc, XE_GPU_REG_SQ_CONTEXT_MISC);
|
||||||
|
dirty |= regs.vertex_shader != active_vertex_shader_;
|
||||||
|
dirty |= regs.pixel_shader != active_pixel_shader_;
|
||||||
|
dirty |= regs.prim_type != prim_type;
|
||||||
|
if (!dirty) {
|
||||||
|
return UpdateStatus::kCompatible;
|
||||||
|
}
|
||||||
|
regs.vertex_shader = static_cast<VulkanShader*>(active_vertex_shader_);
|
||||||
|
regs.pixel_shader = static_cast<VulkanShader*>(active_pixel_shader_);
|
||||||
|
regs.prim_type = prim_type;
|
||||||
|
|
||||||
|
SCOPE_profile_cpu_f("gpu");
|
||||||
|
|
||||||
|
return UpdateStatus::kMismatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanCommandProcessor::UpdateStatus
|
||||||
|
VulkanCommandProcessor::UpdateRenderTargets() {
|
||||||
|
auto& regs = update_render_targets_regs_;
|
||||||
|
|
||||||
|
bool dirty = false;
|
||||||
|
dirty |= SetShadowRegister(®s.rb_modecontrol, XE_GPU_REG_RB_MODECONTROL);
|
||||||
|
dirty |= SetShadowRegister(®s.rb_surface_info, XE_GPU_REG_RB_SURFACE_INFO);
|
||||||
|
dirty |= SetShadowRegister(®s.rb_color_info, XE_GPU_REG_RB_COLOR_INFO);
|
||||||
|
dirty |= SetShadowRegister(®s.rb_color1_info, XE_GPU_REG_RB_COLOR1_INFO);
|
||||||
|
dirty |= SetShadowRegister(®s.rb_color2_info, XE_GPU_REG_RB_COLOR2_INFO);
|
||||||
|
dirty |= SetShadowRegister(®s.rb_color3_info, XE_GPU_REG_RB_COLOR3_INFO);
|
||||||
|
dirty |= SetShadowRegister(®s.rb_color_mask, XE_GPU_REG_RB_COLOR_MASK);
|
||||||
|
dirty |= SetShadowRegister(®s.rb_depthcontrol, XE_GPU_REG_RB_DEPTHCONTROL);
|
||||||
|
dirty |=
|
||||||
|
SetShadowRegister(®s.rb_stencilrefmask, XE_GPU_REG_RB_STENCILREFMASK);
|
||||||
|
dirty |= SetShadowRegister(®s.rb_depth_info, XE_GPU_REG_RB_DEPTH_INFO);
|
||||||
|
if (!dirty) {
|
||||||
|
return UpdateStatus::kCompatible;
|
||||||
|
}
|
||||||
|
|
||||||
|
SCOPE_profile_cpu_f("gpu");
|
||||||
|
|
||||||
|
return UpdateStatus::kMismatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanCommandProcessor::UpdateStatus VulkanCommandProcessor::UpdateState(
|
||||||
|
PrimitiveType prim_type) {
|
||||||
|
bool mismatch = false;
|
||||||
|
|
||||||
|
#define CHECK_UPDATE_STATUS(status, mismatch, error_message) \
|
||||||
|
{ \
|
||||||
|
if (status == UpdateStatus::kError) { \
|
||||||
|
XELOGE(error_message); \
|
||||||
|
return status; \
|
||||||
|
} else if (status == UpdateStatus::kMismatch) { \
|
||||||
|
mismatch = true; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateStatus status;
|
||||||
|
status = UpdateViewportState();
|
||||||
|
CHECK_UPDATE_STATUS(status, mismatch, "Unable to update viewport state");
|
||||||
|
status = UpdateRasterizerState(prim_type);
|
||||||
|
CHECK_UPDATE_STATUS(status, mismatch, "Unable to update rasterizer state");
|
||||||
|
status = UpdateBlendState();
|
||||||
|
CHECK_UPDATE_STATUS(status, mismatch, "Unable to update blend state");
|
||||||
|
status = UpdateDepthStencilState();
|
||||||
|
CHECK_UPDATE_STATUS(status, mismatch, "Unable to update depth/stencil state");
|
||||||
|
|
||||||
|
return mismatch ? UpdateStatus::kMismatch : UpdateStatus::kCompatible;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanCommandProcessor::UpdateStatus
|
||||||
|
VulkanCommandProcessor::UpdateViewportState() {
|
||||||
|
auto& regs = update_viewport_state_regs_;
|
||||||
|
|
||||||
|
bool dirty = false;
|
||||||
|
// dirty |= SetShadowRegister(&state_regs.pa_cl_clip_cntl,
|
||||||
|
// XE_GPU_REG_PA_CL_CLIP_CNTL);
|
||||||
|
dirty |= SetShadowRegister(®s.rb_surface_info, XE_GPU_REG_RB_SURFACE_INFO);
|
||||||
|
dirty |= SetShadowRegister(®s.pa_cl_vte_cntl, XE_GPU_REG_PA_CL_VTE_CNTL);
|
||||||
|
dirty |= SetShadowRegister(®s.pa_su_sc_mode_cntl,
|
||||||
|
XE_GPU_REG_PA_SU_SC_MODE_CNTL);
|
||||||
|
dirty |= SetShadowRegister(®s.pa_sc_window_offset,
|
||||||
|
XE_GPU_REG_PA_SC_WINDOW_OFFSET);
|
||||||
|
dirty |= SetShadowRegister(®s.pa_sc_window_scissor_tl,
|
||||||
|
XE_GPU_REG_PA_SC_WINDOW_SCISSOR_TL);
|
||||||
|
dirty |= SetShadowRegister(®s.pa_sc_window_scissor_br,
|
||||||
|
XE_GPU_REG_PA_SC_WINDOW_SCISSOR_BR);
|
||||||
|
dirty |= SetShadowRegister(®s.pa_cl_vport_xoffset,
|
||||||
|
XE_GPU_REG_PA_CL_VPORT_XOFFSET);
|
||||||
|
dirty |= SetShadowRegister(®s.pa_cl_vport_yoffset,
|
||||||
|
XE_GPU_REG_PA_CL_VPORT_YOFFSET);
|
||||||
|
dirty |= SetShadowRegister(®s.pa_cl_vport_zoffset,
|
||||||
|
XE_GPU_REG_PA_CL_VPORT_ZOFFSET);
|
||||||
|
dirty |= SetShadowRegister(®s.pa_cl_vport_xscale,
|
||||||
|
XE_GPU_REG_PA_CL_VPORT_XSCALE);
|
||||||
|
dirty |= SetShadowRegister(®s.pa_cl_vport_yscale,
|
||||||
|
XE_GPU_REG_PA_CL_VPORT_YSCALE);
|
||||||
|
dirty |= SetShadowRegister(®s.pa_cl_vport_zscale,
|
||||||
|
XE_GPU_REG_PA_CL_VPORT_ZSCALE);
|
||||||
|
|
||||||
|
// Much of this state machine is extracted from:
|
||||||
|
// https://github.com/freedreno/mesa/blob/master/src/mesa/drivers/dri/r200/r200_state.c
|
||||||
|
// http://fossies.org/dox/MesaLib-10.3.5/fd2__gmem_8c_source.html
|
||||||
|
// http://www.x.org/docs/AMD/old/evergreen_3D_registers_v2.pdf
|
||||||
|
|
||||||
|
// http://www.x.org/docs/AMD/old/evergreen_3D_registers_v2.pdf
|
||||||
|
// VTX_XY_FMT = true: the incoming X, Y have already been multiplied by 1/W0.
|
||||||
|
// = false: multiply the X, Y coordinates by 1/W0.
|
||||||
|
// VTX_Z_FMT = true: the incoming Z has already been multiplied by 1/W0.
|
||||||
|
// = false: multiply the Z coordinate by 1/W0.
|
||||||
|
// VTX_W0_FMT = true: the incoming W0 is not 1/W0. Perform the reciprocal to
|
||||||
|
// get 1/W0.
|
||||||
|
// draw_batcher_.set_vtx_fmt((regs.pa_cl_vte_cntl >> 8) & 0x1 ? 1.0f : 0.0f,
|
||||||
|
// (regs.pa_cl_vte_cntl >> 9) & 0x1 ? 1.0f : 0.0f,
|
||||||
|
// (regs.pa_cl_vte_cntl >> 10) & 0x1 ? 1.0f : 0.0f);
|
||||||
|
|
||||||
|
// Done in VS, no need to flush state.
|
||||||
|
// if ((regs.pa_cl_vte_cntl & (1 << 0)) > 0) {
|
||||||
|
// draw_batcher_.set_window_scalar(1.0f, 1.0f);
|
||||||
|
//} else {
|
||||||
|
// draw_batcher_.set_window_scalar(1.0f / 2560.0f, -1.0f / 2560.0f);
|
||||||
|
//}
|
||||||
|
|
||||||
|
if (!dirty) {
|
||||||
|
return UpdateStatus::kCompatible;
|
||||||
|
}
|
||||||
|
|
||||||
|
return UpdateStatus::kMismatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanCommandProcessor::UpdateStatus
|
||||||
|
VulkanCommandProcessor::UpdateRasterizerState(PrimitiveType prim_type) {
|
||||||
|
auto& regs = update_rasterizer_state_regs_;
|
||||||
|
|
||||||
|
bool dirty = false;
|
||||||
|
dirty |= SetShadowRegister(®s.pa_su_sc_mode_cntl,
|
||||||
|
XE_GPU_REG_PA_SU_SC_MODE_CNTL);
|
||||||
|
dirty |= SetShadowRegister(®s.pa_sc_screen_scissor_tl,
|
||||||
|
XE_GPU_REG_PA_SC_SCREEN_SCISSOR_TL);
|
||||||
|
dirty |= SetShadowRegister(®s.pa_sc_screen_scissor_br,
|
||||||
|
XE_GPU_REG_PA_SC_SCREEN_SCISSOR_BR);
|
||||||
|
dirty |= SetShadowRegister(®s.multi_prim_ib_reset_index,
|
||||||
|
XE_GPU_REG_VGT_MULTI_PRIM_IB_RESET_INDX);
|
||||||
|
dirty |= regs.prim_type != prim_type;
|
||||||
|
if (!dirty) {
|
||||||
|
return UpdateStatus::kCompatible;
|
||||||
|
}
|
||||||
|
|
||||||
|
regs.prim_type = prim_type;
|
||||||
|
|
||||||
|
SCOPE_profile_cpu_f("gpu");
|
||||||
|
|
||||||
|
return UpdateStatus::kMismatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanCommandProcessor::UpdateStatus
|
||||||
|
VulkanCommandProcessor::UpdateBlendState() {
|
||||||
|
auto& reg_file = *register_file_;
|
||||||
|
auto& regs = update_blend_state_regs_;
|
||||||
|
|
||||||
|
// Alpha testing -- ALPHAREF, ALPHAFUNC, ALPHATESTENABLE
|
||||||
|
// Deprecated in GL, implemented in shader.
|
||||||
|
// if(ALPHATESTENABLE && frag_out.a [<=/ALPHAFUNC] ALPHAREF) discard;
|
||||||
|
// uint32_t color_control = reg_file[XE_GPU_REG_RB_COLORCONTROL].u32;
|
||||||
|
// draw_batcher_.set_alpha_test((color_control & 0x4) != 0, //
|
||||||
|
// ALPAHTESTENABLE
|
||||||
|
// color_control & 0x7, // ALPHAFUNC
|
||||||
|
// reg_file[XE_GPU_REG_RB_ALPHA_REF].f32);
|
||||||
|
|
||||||
|
bool dirty = false;
|
||||||
|
dirty |=
|
||||||
|
SetShadowRegister(®s.rb_blendcontrol[0], XE_GPU_REG_RB_BLENDCONTROL_0);
|
||||||
|
dirty |=
|
||||||
|
SetShadowRegister(®s.rb_blendcontrol[1], XE_GPU_REG_RB_BLENDCONTROL_1);
|
||||||
|
dirty |=
|
||||||
|
SetShadowRegister(®s.rb_blendcontrol[2], XE_GPU_REG_RB_BLENDCONTROL_2);
|
||||||
|
dirty |=
|
||||||
|
SetShadowRegister(®s.rb_blendcontrol[3], XE_GPU_REG_RB_BLENDCONTROL_3);
|
||||||
|
dirty |= SetShadowRegister(®s.rb_blend_rgba[0], XE_GPU_REG_RB_BLEND_RED);
|
||||||
|
dirty |= SetShadowRegister(®s.rb_blend_rgba[1], XE_GPU_REG_RB_BLEND_GREEN);
|
||||||
|
dirty |= SetShadowRegister(®s.rb_blend_rgba[2], XE_GPU_REG_RB_BLEND_BLUE);
|
||||||
|
dirty |= SetShadowRegister(®s.rb_blend_rgba[3], XE_GPU_REG_RB_BLEND_ALPHA);
|
||||||
|
if (!dirty) {
|
||||||
|
return UpdateStatus::kCompatible;
|
||||||
|
}
|
||||||
|
|
||||||
|
SCOPE_profile_cpu_f("gpu");
|
||||||
|
|
||||||
|
return UpdateStatus::kMismatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanCommandProcessor::UpdateStatus
|
||||||
|
VulkanCommandProcessor::UpdateDepthStencilState() {
|
||||||
|
auto& regs = update_depth_stencil_state_regs_;
|
||||||
|
|
||||||
|
bool dirty = false;
|
||||||
|
dirty |= SetShadowRegister(®s.rb_depthcontrol, XE_GPU_REG_RB_DEPTHCONTROL);
|
||||||
|
dirty |=
|
||||||
|
SetShadowRegister(®s.rb_stencilrefmask, XE_GPU_REG_RB_STENCILREFMASK);
|
||||||
|
if (!dirty) {
|
||||||
|
return UpdateStatus::kCompatible;
|
||||||
|
}
|
||||||
|
|
||||||
|
SCOPE_profile_cpu_f("gpu");
|
||||||
|
|
||||||
|
return UpdateStatus::kMismatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanCommandProcessor::UpdateStatus
|
||||||
|
VulkanCommandProcessor::PopulateIndexBuffer(
|
||||||
|
IndexBufferInfo* index_buffer_info) {
|
||||||
|
auto& regs = *register_file_;
|
||||||
|
if (!index_buffer_info || !index_buffer_info->guest_base) {
|
||||||
|
// No index buffer or auto draw.
|
||||||
|
return UpdateStatus::kCompatible;
|
||||||
|
}
|
||||||
|
auto& info = *index_buffer_info;
|
||||||
|
|
||||||
|
#if FINE_GRAINED_DRAW_SCOPES
|
||||||
|
SCOPE_profile_cpu_f("gpu");
|
||||||
|
#endif // FINE_GRAINED_DRAW_SCOPES
|
||||||
|
|
||||||
|
// Min/max index ranges for clamping. This is often [0g,FFFF|FFFFFF].
|
||||||
|
// All indices should be clamped to [min,max]. May be a way to do this in GL.
|
||||||
|
uint32_t min_index = regs[XE_GPU_REG_VGT_MIN_VTX_INDX].u32;
|
||||||
|
uint32_t max_index = regs[XE_GPU_REG_VGT_MAX_VTX_INDX].u32;
|
||||||
|
assert_true(min_index == 0);
|
||||||
|
assert_true(max_index == 0xFFFF || max_index == 0xFFFFFF);
|
||||||
|
|
||||||
|
assert_true(info.endianness == Endian::k8in16 ||
|
||||||
|
info.endianness == Endian::k8in32);
|
||||||
|
|
||||||
|
trace_writer_.WriteMemoryRead(info.guest_base, info.length);
|
||||||
|
|
||||||
|
return UpdateStatus::kCompatible;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanCommandProcessor::UpdateStatus
|
||||||
|
VulkanCommandProcessor::PopulateVertexBuffers() {
|
||||||
|
#if FINE_GRAINED_DRAW_SCOPES
|
||||||
|
SCOPE_profile_cpu_f("gpu");
|
||||||
|
#endif // FINE_GRAINED_DRAW_SCOPES
|
||||||
|
|
||||||
|
auto& regs = *register_file_;
|
||||||
|
assert_not_null(active_vertex_shader_);
|
||||||
|
|
||||||
|
for (const auto& vertex_binding : active_vertex_shader_->vertex_bindings()) {
|
||||||
|
int r = XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 +
|
||||||
|
(vertex_binding.fetch_constant / 3) * 6;
|
||||||
|
const auto group = reinterpret_cast<xe_gpu_fetch_group_t*>(®s.values[r]);
|
||||||
|
const xe_gpu_vertex_fetch_t* fetch = nullptr;
|
||||||
|
switch (vertex_binding.fetch_constant % 3) {
|
||||||
|
case 0:
|
||||||
|
fetch = &group->vertex_fetch_0;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
fetch = &group->vertex_fetch_1;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
fetch = &group->vertex_fetch_2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
assert_true(fetch->endian == 2);
|
||||||
|
|
||||||
|
size_t valid_range = size_t(fetch->size * 4);
|
||||||
|
|
||||||
|
trace_writer_.WriteMemoryRead(fetch->address << 2, valid_range);
|
||||||
|
}
|
||||||
|
|
||||||
|
return UpdateStatus::kCompatible;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanCommandProcessor::UpdateStatus
|
||||||
|
VulkanCommandProcessor::PopulateSamplers() {
|
||||||
|
#if FINE_GRAINED_DRAW_SCOPES
|
||||||
|
SCOPE_profile_cpu_f("gpu");
|
||||||
|
#endif // FINE_GRAINED_DRAW_SCOPES
|
||||||
|
|
||||||
|
bool mismatch = false;
|
||||||
|
|
||||||
|
// VS and PS samplers are shared, but may be used exclusively.
|
||||||
|
// We walk each and setup lazily.
|
||||||
|
bool has_setup_sampler[32] = {false};
|
||||||
|
|
||||||
|
// Vertex texture samplers.
|
||||||
|
for (auto& texture_binding : active_vertex_shader_->texture_bindings()) {
|
||||||
|
if (has_setup_sampler[texture_binding.fetch_constant]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
has_setup_sampler[texture_binding.fetch_constant] = true;
|
||||||
|
auto status = PopulateSampler(texture_binding);
|
||||||
|
if (status == UpdateStatus::kError) {
|
||||||
|
return status;
|
||||||
|
} else if (status == UpdateStatus::kMismatch) {
|
||||||
|
mismatch = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pixel shader texture sampler.
|
||||||
|
for (auto& texture_binding : active_pixel_shader_->texture_bindings()) {
|
||||||
|
if (has_setup_sampler[texture_binding.fetch_constant]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
has_setup_sampler[texture_binding.fetch_constant] = true;
|
||||||
|
auto status = PopulateSampler(texture_binding);
|
||||||
|
if (status == UpdateStatus::kError) {
|
||||||
|
return UpdateStatus::kError;
|
||||||
|
} else if (status == UpdateStatus::kMismatch) {
|
||||||
|
mismatch = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mismatch ? UpdateStatus::kMismatch : UpdateStatus::kCompatible;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanCommandProcessor::UpdateStatus VulkanCommandProcessor::PopulateSampler(
|
||||||
|
const Shader::TextureBinding& texture_binding) {
|
||||||
|
auto& regs = *register_file_;
|
||||||
|
int r = XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 +
|
||||||
|
texture_binding.fetch_constant * 6;
|
||||||
|
auto group = reinterpret_cast<const xe_gpu_fetch_group_t*>(®s.values[r]);
|
||||||
|
auto& fetch = group->texture_fetch;
|
||||||
|
|
||||||
|
// ?
|
||||||
|
if (!fetch.type) {
|
||||||
|
return UpdateStatus::kCompatible;
|
||||||
|
}
|
||||||
|
assert_true(fetch.type == 0x2);
|
||||||
|
|
||||||
|
TextureInfo texture_info;
|
||||||
|
if (!TextureInfo::Prepare(fetch, &texture_info)) {
|
||||||
|
XELOGE("Unable to parse texture fetcher info");
|
||||||
|
return UpdateStatus::kCompatible; // invalid texture used
|
||||||
|
}
|
||||||
|
SamplerInfo sampler_info;
|
||||||
|
if (!SamplerInfo::Prepare(fetch, texture_binding.fetch_instr,
|
||||||
|
&sampler_info)) {
|
||||||
|
XELOGE("Unable to parse sampler info");
|
||||||
|
return UpdateStatus::kCompatible; // invalid texture used
|
||||||
|
}
|
||||||
|
|
||||||
|
trace_writer_.WriteMemoryRead(texture_info.guest_address,
|
||||||
|
texture_info.input_length);
|
||||||
|
|
||||||
|
return UpdateStatus::kCompatible;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VulkanCommandProcessor::IssueCopy() {
|
||||||
|
SCOPE_profile_cpu_f("gpu");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace vulkan
|
||||||
|
} // namespace gpu
|
||||||
|
} // namespace xe
|
|
@ -0,0 +1,165 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2016 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XENIA_GPU_VULKAN_COMMAND_PROCESSOR_H_
|
||||||
|
#define XENIA_GPU_VULKAN_COMMAND_PROCESSOR_H_
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <cstring>
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <queue>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "xenia/base/threading.h"
|
||||||
|
#include "xenia/gpu/command_processor.h"
|
||||||
|
#include "xenia/gpu/register_file.h"
|
||||||
|
#include "xenia/gpu/spirv_shader_translator.h"
|
||||||
|
#include "xenia/gpu/vulkan/vulkan_shader.h"
|
||||||
|
#include "xenia/gpu/xenos.h"
|
||||||
|
#include "xenia/kernel/xthread.h"
|
||||||
|
#include "xenia/memory.h"
|
||||||
|
#include "xenia/ui/vulkan/vulkan_context.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace gpu {
|
||||||
|
namespace vulkan {
|
||||||
|
|
||||||
|
class VulkanGraphicsSystem;
|
||||||
|
|
||||||
|
class VulkanCommandProcessor : public CommandProcessor {
|
||||||
|
public:
|
||||||
|
VulkanCommandProcessor(VulkanGraphicsSystem* graphics_system,
|
||||||
|
kernel::KernelState* kernel_state);
|
||||||
|
~VulkanCommandProcessor() override;
|
||||||
|
|
||||||
|
void ClearCaches() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum class UpdateStatus {
|
||||||
|
kCompatible,
|
||||||
|
kMismatch,
|
||||||
|
kError,
|
||||||
|
};
|
||||||
|
|
||||||
|
bool SetupContext() override;
|
||||||
|
void ShutdownContext() override;
|
||||||
|
|
||||||
|
void MakeCoherent() override;
|
||||||
|
void PrepareForWait() override;
|
||||||
|
void ReturnFromWait() override;
|
||||||
|
|
||||||
|
void PerformSwap(uint32_t frontbuffer_ptr, uint32_t frontbuffer_width,
|
||||||
|
uint32_t frontbuffer_height) override;
|
||||||
|
|
||||||
|
Shader* LoadShader(ShaderType shader_type, uint32_t guest_address,
|
||||||
|
const uint32_t* host_address,
|
||||||
|
uint32_t dword_count) override;
|
||||||
|
|
||||||
|
bool IssueDraw(PrimitiveType prim_type, uint32_t index_count,
|
||||||
|
IndexBufferInfo* index_buffer_info) override;
|
||||||
|
UpdateStatus UpdateShaders(PrimitiveType prim_type);
|
||||||
|
UpdateStatus UpdateRenderTargets();
|
||||||
|
UpdateStatus UpdateState(PrimitiveType prim_type);
|
||||||
|
UpdateStatus UpdateViewportState();
|
||||||
|
UpdateStatus UpdateRasterizerState(PrimitiveType prim_type);
|
||||||
|
UpdateStatus UpdateBlendState();
|
||||||
|
UpdateStatus UpdateDepthStencilState();
|
||||||
|
UpdateStatus PopulateIndexBuffer(IndexBufferInfo* index_buffer_info);
|
||||||
|
UpdateStatus PopulateVertexBuffers();
|
||||||
|
UpdateStatus PopulateSamplers();
|
||||||
|
UpdateStatus PopulateSampler(const Shader::TextureBinding& texture_binding);
|
||||||
|
bool IssueCopy() override;
|
||||||
|
|
||||||
|
SpirvShaderTranslator shader_translator_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool SetShadowRegister(uint32_t* dest, uint32_t register_name);
|
||||||
|
bool SetShadowRegister(float* dest, uint32_t register_name);
|
||||||
|
struct UpdateRenderTargetsRegisters {
|
||||||
|
uint32_t rb_modecontrol;
|
||||||
|
uint32_t rb_surface_info;
|
||||||
|
uint32_t rb_color_info;
|
||||||
|
uint32_t rb_color1_info;
|
||||||
|
uint32_t rb_color2_info;
|
||||||
|
uint32_t rb_color3_info;
|
||||||
|
uint32_t rb_color_mask;
|
||||||
|
uint32_t rb_depthcontrol;
|
||||||
|
uint32_t rb_stencilrefmask;
|
||||||
|
uint32_t rb_depth_info;
|
||||||
|
|
||||||
|
UpdateRenderTargetsRegisters() { Reset(); }
|
||||||
|
void Reset() { std::memset(this, 0, sizeof(*this)); }
|
||||||
|
} update_render_targets_regs_;
|
||||||
|
struct UpdateViewportStateRegisters {
|
||||||
|
// uint32_t pa_cl_clip_cntl;
|
||||||
|
uint32_t rb_surface_info;
|
||||||
|
uint32_t pa_cl_vte_cntl;
|
||||||
|
uint32_t pa_su_sc_mode_cntl;
|
||||||
|
uint32_t pa_sc_window_offset;
|
||||||
|
uint32_t pa_sc_window_scissor_tl;
|
||||||
|
uint32_t pa_sc_window_scissor_br;
|
||||||
|
float pa_cl_vport_xoffset;
|
||||||
|
float pa_cl_vport_yoffset;
|
||||||
|
float pa_cl_vport_zoffset;
|
||||||
|
float pa_cl_vport_xscale;
|
||||||
|
float pa_cl_vport_yscale;
|
||||||
|
float pa_cl_vport_zscale;
|
||||||
|
|
||||||
|
UpdateViewportStateRegisters() { Reset(); }
|
||||||
|
void Reset() { std::memset(this, 0, sizeof(*this)); }
|
||||||
|
} update_viewport_state_regs_;
|
||||||
|
struct UpdateRasterizerStateRegisters {
|
||||||
|
uint32_t pa_su_sc_mode_cntl;
|
||||||
|
uint32_t pa_sc_screen_scissor_tl;
|
||||||
|
uint32_t pa_sc_screen_scissor_br;
|
||||||
|
uint32_t multi_prim_ib_reset_index;
|
||||||
|
PrimitiveType prim_type;
|
||||||
|
|
||||||
|
UpdateRasterizerStateRegisters() { Reset(); }
|
||||||
|
void Reset() { std::memset(this, 0, sizeof(*this)); }
|
||||||
|
} update_rasterizer_state_regs_;
|
||||||
|
struct UpdateBlendStateRegisters {
|
||||||
|
uint32_t rb_blendcontrol[4];
|
||||||
|
float rb_blend_rgba[4];
|
||||||
|
|
||||||
|
UpdateBlendStateRegisters() { Reset(); }
|
||||||
|
void Reset() { std::memset(this, 0, sizeof(*this)); }
|
||||||
|
} update_blend_state_regs_;
|
||||||
|
struct UpdateDepthStencilStateRegisters {
|
||||||
|
uint32_t rb_depthcontrol;
|
||||||
|
uint32_t rb_stencilrefmask;
|
||||||
|
|
||||||
|
UpdateDepthStencilStateRegisters() { Reset(); }
|
||||||
|
void Reset() { std::memset(this, 0, sizeof(*this)); }
|
||||||
|
} update_depth_stencil_state_regs_;
|
||||||
|
struct UpdateShadersRegisters {
|
||||||
|
PrimitiveType prim_type;
|
||||||
|
uint32_t pa_su_sc_mode_cntl;
|
||||||
|
uint32_t sq_program_cntl;
|
||||||
|
uint32_t sq_context_misc;
|
||||||
|
VulkanShader* vertex_shader;
|
||||||
|
VulkanShader* pixel_shader;
|
||||||
|
|
||||||
|
UpdateShadersRegisters() { Reset(); }
|
||||||
|
void Reset() {
|
||||||
|
sq_program_cntl = 0;
|
||||||
|
vertex_shader = pixel_shader = nullptr;
|
||||||
|
}
|
||||||
|
} update_shaders_regs_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace vulkan
|
||||||
|
} // namespace gpu
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
#endif // XENIA_GPU_VULKAN_COMMAND_PROCESSOR_H_
|
|
@ -0,0 +1,10 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2016 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xenia/gpu/vulkan/vulkan_gpu_flags.h"
|
|
@ -0,0 +1,15 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2016 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XENIA_GPU_VULKAN_VULKAN_GPU_FLAGS_H_
|
||||||
|
#define XENIA_GPU_VULKAN_VULKAN_GPU_FLAGS_H_
|
||||||
|
|
||||||
|
#include <gflags/gflags.h>
|
||||||
|
|
||||||
|
#endif // XENIA_GPU_VULKAN_VULKAN_GPU_FLAGS_H_
|
|
@ -0,0 +1,87 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2016 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xenia/gpu/vulkan/vulkan_graphics_system.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "xenia/base/logging.h"
|
||||||
|
#include "xenia/base/profiling.h"
|
||||||
|
#include "xenia/cpu/processor.h"
|
||||||
|
#include "xenia/gpu/gpu_flags.h"
|
||||||
|
#include "xenia/gpu/vulkan/vulkan_command_processor.h"
|
||||||
|
#include "xenia/gpu/vulkan/vulkan_gpu_flags.h"
|
||||||
|
#include "xenia/ui/vulkan/vulkan_provider.h"
|
||||||
|
#include "xenia/ui/window.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace gpu {
|
||||||
|
namespace vulkan {
|
||||||
|
|
||||||
|
VulkanGraphicsSystem::VulkanGraphicsSystem() = default;
|
||||||
|
|
||||||
|
VulkanGraphicsSystem::~VulkanGraphicsSystem() = default;
|
||||||
|
|
||||||
|
X_STATUS VulkanGraphicsSystem::Setup(cpu::Processor* processor,
|
||||||
|
kernel::KernelState* kernel_state,
|
||||||
|
ui::Window* target_window) {
|
||||||
|
// Must create the provider so we can create contexts.
|
||||||
|
provider_ = xe::ui::vulkan::VulkanProvider::Create(target_window);
|
||||||
|
|
||||||
|
auto result = GraphicsSystem::Setup(processor, kernel_state, target_window);
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
display_context_ = reinterpret_cast<xe::ui::vulkan::VulkanContext*>(
|
||||||
|
target_window->context());
|
||||||
|
|
||||||
|
return X_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanGraphicsSystem::Shutdown() { GraphicsSystem::Shutdown(); }
|
||||||
|
|
||||||
|
std::unique_ptr<CommandProcessor>
|
||||||
|
VulkanGraphicsSystem::CreateCommandProcessor() {
|
||||||
|
return std::unique_ptr<CommandProcessor>(
|
||||||
|
new VulkanCommandProcessor(this, kernel_state_));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanGraphicsSystem::Swap(xe::ui::UIEvent* e) {
|
||||||
|
if (!command_processor_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Check for pending swap.
|
||||||
|
auto& swap_state = command_processor_->swap_state();
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(swap_state.mutex);
|
||||||
|
if (swap_state.pending) {
|
||||||
|
swap_state.pending = false;
|
||||||
|
std::swap(swap_state.front_buffer_texture,
|
||||||
|
swap_state.back_buffer_texture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!swap_state.front_buffer_texture) {
|
||||||
|
// Not yet ready.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blit the frontbuffer.
|
||||||
|
// display_context_->blitter()->BlitTexture2D(
|
||||||
|
// static_cast<GLuint>(swap_state.front_buffer_texture),
|
||||||
|
// Rect2D(0, 0, swap_state.width, swap_state.height),
|
||||||
|
// Rect2D(0, 0, target_window_->width(), target_window_->height()),
|
||||||
|
// GL_LINEAR, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace vulkan
|
||||||
|
} // namespace gpu
|
||||||
|
} // namespace xe
|
|
@ -0,0 +1,43 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2016 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XENIA_GPU_VULKAN_VULKAN_GRAPHICS_SYSTEM_H_
|
||||||
|
#define XENIA_GPU_VULKAN_VULKAN_GRAPHICS_SYSTEM_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "xenia/gpu/graphics_system.h"
|
||||||
|
#include "xenia/ui/vulkan/vulkan_context.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace gpu {
|
||||||
|
namespace vulkan {
|
||||||
|
|
||||||
|
class VulkanGraphicsSystem : public GraphicsSystem {
|
||||||
|
public:
|
||||||
|
VulkanGraphicsSystem();
|
||||||
|
~VulkanGraphicsSystem() override;
|
||||||
|
|
||||||
|
X_STATUS Setup(cpu::Processor* processor, kernel::KernelState* kernel_state,
|
||||||
|
ui::Window* target_window) override;
|
||||||
|
void Shutdown() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<CommandProcessor> CreateCommandProcessor() override;
|
||||||
|
|
||||||
|
void Swap(xe::ui::UIEvent* e) override;
|
||||||
|
|
||||||
|
xe::ui::vulkan::VulkanContext* display_context_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace vulkan
|
||||||
|
} // namespace gpu
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
#endif // XENIA_GPU_VULKAN_VULKAN_GRAPHICS_SYSTEM_H_
|
|
@ -0,0 +1,27 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2016 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xenia/gpu/vulkan/vulkan_shader.h"
|
||||||
|
|
||||||
|
#include "xenia/base/logging.h"
|
||||||
|
#include "xenia/base/math.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace gpu {
|
||||||
|
namespace vulkan {
|
||||||
|
|
||||||
|
VulkanShader::VulkanShader(ShaderType shader_type, uint64_t data_hash,
|
||||||
|
const uint32_t* dword_ptr, uint32_t dword_count)
|
||||||
|
: Shader(shader_type, data_hash, dword_ptr, dword_count) {}
|
||||||
|
|
||||||
|
VulkanShader::~VulkanShader() = default;
|
||||||
|
|
||||||
|
} // namespace vulkan
|
||||||
|
} // namespace gpu
|
||||||
|
} // namespace xe
|
|
@ -0,0 +1,33 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2016 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XENIA_GPU_VULKAN_VULKAN_SHADER_H_
|
||||||
|
#define XENIA_GPU_VULKAN_VULKAN_SHADER_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "xenia/gpu/shader.h"
|
||||||
|
#include "xenia/ui/vulkan/vulkan_context.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace gpu {
|
||||||
|
namespace vulkan {
|
||||||
|
|
||||||
|
class VulkanShader : public Shader {
|
||||||
|
public:
|
||||||
|
VulkanShader(ShaderType shader_type, uint64_t data_hash,
|
||||||
|
const uint32_t* dword_ptr, uint32_t dword_count);
|
||||||
|
~VulkanShader() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace vulkan
|
||||||
|
} // namespace gpu
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
#endif // XENIA_GPU_VULKAN_VULKAN_SHADER_H_
|
|
@ -0,0 +1,76 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2016 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xenia/base/logging.h"
|
||||||
|
#include "xenia/base/main.h"
|
||||||
|
#include "xenia/gpu/trace_dump.h"
|
||||||
|
#include "xenia/gpu/vulkan/vulkan_command_processor.h"
|
||||||
|
#include "xenia/gpu/vulkan/vulkan_graphics_system.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace gpu {
|
||||||
|
namespace vulkan {
|
||||||
|
|
||||||
|
using namespace xe::gpu::xenos;
|
||||||
|
|
||||||
|
class VulkanTraceDump : public TraceDump {
|
||||||
|
public:
|
||||||
|
std::unique_ptr<gpu::GraphicsSystem> CreateGraphicsSystem() override {
|
||||||
|
return std::unique_ptr<gpu::GraphicsSystem>(new VulkanGraphicsSystem());
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t GetColorRenderTarget(uint32_t pitch, MsaaSamples samples,
|
||||||
|
uint32_t base,
|
||||||
|
ColorRenderTargetFormat format) override {
|
||||||
|
auto command_processor = static_cast<VulkanCommandProcessor*>(
|
||||||
|
graphics_system_->command_processor());
|
||||||
|
// return command_processor->GetColorRenderTarget(pitch, samples, base,
|
||||||
|
// format);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t GetDepthRenderTarget(uint32_t pitch, MsaaSamples samples,
|
||||||
|
uint32_t base,
|
||||||
|
DepthRenderTargetFormat format) override {
|
||||||
|
auto command_processor = static_cast<VulkanCommandProcessor*>(
|
||||||
|
graphics_system_->command_processor());
|
||||||
|
// return command_processor->GetDepthRenderTarget(pitch, samples, base,
|
||||||
|
// format);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t GetTextureEntry(const TextureInfo& texture_info,
|
||||||
|
const SamplerInfo& sampler_info) override {
|
||||||
|
auto command_processor = static_cast<VulkanCommandProcessor*>(
|
||||||
|
graphics_system_->command_processor());
|
||||||
|
|
||||||
|
// auto entry_view =
|
||||||
|
// command_processor->texture_cache()->Demand(texture_info,
|
||||||
|
// sampler_info);
|
||||||
|
// if (!entry_view) {
|
||||||
|
// return 0;
|
||||||
|
//}
|
||||||
|
// auto texture = entry_view->texture;
|
||||||
|
// return static_cast<uintptr_t>(texture->handle);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int trace_dump_main(const std::vector<std::wstring>& args) {
|
||||||
|
VulkanTraceDump trace_dump;
|
||||||
|
return trace_dump.Main(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace vulkan
|
||||||
|
} // namespace gpu
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
DEFINE_ENTRY_POINT(L"xenia-gpu-vulkan-trace-dump",
|
||||||
|
L"xenia-gpu-vulkan-trace-dump some.trace",
|
||||||
|
xe::gpu::vulkan::trace_dump_main);
|
|
@ -0,0 +1,76 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2016 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xenia/base/logging.h"
|
||||||
|
#include "xenia/base/main.h"
|
||||||
|
#include "xenia/gpu/trace_viewer.h"
|
||||||
|
#include "xenia/gpu/vulkan/vulkan_command_processor.h"
|
||||||
|
#include "xenia/gpu/vulkan/vulkan_graphics_system.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace gpu {
|
||||||
|
namespace vulkan {
|
||||||
|
|
||||||
|
using namespace xe::gpu::xenos;
|
||||||
|
|
||||||
|
class VulkanTraceViewer : public TraceViewer {
|
||||||
|
public:
|
||||||
|
std::unique_ptr<gpu::GraphicsSystem> CreateGraphicsSystem() override {
|
||||||
|
return std::unique_ptr<gpu::GraphicsSystem>(new VulkanGraphicsSystem());
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t GetColorRenderTarget(uint32_t pitch, MsaaSamples samples,
|
||||||
|
uint32_t base,
|
||||||
|
ColorRenderTargetFormat format) override {
|
||||||
|
auto command_processor = static_cast<VulkanCommandProcessor*>(
|
||||||
|
graphics_system_->command_processor());
|
||||||
|
// return command_processor->GetColorRenderTarget(pitch, samples, base,
|
||||||
|
// format);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t GetDepthRenderTarget(uint32_t pitch, MsaaSamples samples,
|
||||||
|
uint32_t base,
|
||||||
|
DepthRenderTargetFormat format) override {
|
||||||
|
auto command_processor = static_cast<VulkanCommandProcessor*>(
|
||||||
|
graphics_system_->command_processor());
|
||||||
|
// return command_processor->GetDepthRenderTarget(pitch, samples, base,
|
||||||
|
// format);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t GetTextureEntry(const TextureInfo& texture_info,
|
||||||
|
const SamplerInfo& sampler_info) override {
|
||||||
|
auto command_processor = static_cast<VulkanCommandProcessor*>(
|
||||||
|
graphics_system_->command_processor());
|
||||||
|
|
||||||
|
// auto entry_view =
|
||||||
|
// command_processor->texture_cache()->Demand(texture_info,
|
||||||
|
// sampler_info);
|
||||||
|
// if (!entry_view) {
|
||||||
|
// return 0;
|
||||||
|
//}
|
||||||
|
// auto texture = entry_view->texture;
|
||||||
|
// return static_cast<uintptr_t>(texture->handle);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int trace_viewer_main(const std::vector<std::wstring>& args) {
|
||||||
|
VulkanTraceViewer trace_viewer;
|
||||||
|
return trace_viewer.Main(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace vulkan
|
||||||
|
} // namespace gpu
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
DEFINE_ENTRY_POINT(L"xenia-gpu-vulkan-trace-viewer",
|
||||||
|
L"xenia-gpu-vulkan-trace-viewer some.trace",
|
||||||
|
xe::gpu::vulkan::trace_viewer_main);
|
|
@ -686,13 +686,13 @@ void VulkanImmediateDrawer::Draw(const ImmediateDraw& draw) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup texture binding.
|
// Setup texture binding.
|
||||||
VkDescriptorSet texture_set = nullptr;
|
|
||||||
auto texture = reinterpret_cast<VulkanImmediateTexture*>(draw.texture_handle);
|
auto texture = reinterpret_cast<VulkanImmediateTexture*>(draw.texture_handle);
|
||||||
if (texture) {
|
if (texture) {
|
||||||
texture_set = texture->descriptor_set();
|
auto texture_set = texture->descriptor_set();
|
||||||
|
vkCmdBindDescriptorSets(current_cmd_buffer_,
|
||||||
|
VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout_,
|
||||||
|
0, 1, &texture_set, 0, nullptr);
|
||||||
}
|
}
|
||||||
vkCmdBindDescriptorSets(current_cmd_buffer_, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
||||||
pipeline_layout_, 0, 1, &texture_set, 0, nullptr);
|
|
||||||
|
|
||||||
// Use push constants for our per-draw changes.
|
// Use push constants for our per-draw changes.
|
||||||
// Here, the restrict_texture_samples uniform.
|
// Here, the restrict_texture_samples uniform.
|
||||||
|
|
Loading…
Reference in New Issue