95% of trace viewer now gpu backend agnostic.
This commit is contained in:
parent
b5a18b5462
commit
9a6c5c5c74
|
@ -1079,8 +1079,20 @@ bool CommandProcessor::ExecutePacketType3_IM_LOAD(RingbufferReader* reader,
|
||||||
uint32_t size_dwords = start_size & 0xFFFF; // dwords
|
uint32_t size_dwords = start_size & 0xFFFF; // dwords
|
||||||
assert_true(start == 0);
|
assert_true(start == 0);
|
||||||
trace_writer_.WriteMemoryRead(CpuToGpu(addr), size_dwords * 4);
|
trace_writer_.WriteMemoryRead(CpuToGpu(addr), size_dwords * 4);
|
||||||
LoadShader(shader_type, addr, memory_->TranslatePhysical<uint32_t*>(addr),
|
auto shader =
|
||||||
size_dwords);
|
LoadShader(shader_type, addr, memory_->TranslatePhysical<uint32_t*>(addr),
|
||||||
|
size_dwords);
|
||||||
|
switch (shader_type) {
|
||||||
|
case ShaderType::kVertex:
|
||||||
|
active_vertex_shader_ = shader;
|
||||||
|
break;
|
||||||
|
case ShaderType::kPixel:
|
||||||
|
active_pixel_shader_ = shader;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert_unhandled_case(shader_type);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1095,8 +1107,20 @@ bool CommandProcessor::ExecutePacketType3_IM_LOAD_IMMEDIATE(
|
||||||
uint32_t size_dwords = start_size & 0xFFFF; // dwords
|
uint32_t size_dwords = start_size & 0xFFFF; // dwords
|
||||||
assert_true(start == 0);
|
assert_true(start == 0);
|
||||||
reader->CheckRead(size_dwords);
|
reader->CheckRead(size_dwords);
|
||||||
LoadShader(shader_type, reader->ptr(),
|
auto shader = LoadShader(shader_type, reader->ptr(),
|
||||||
memory_->TranslatePhysical<uint32_t*>(reader->ptr()), size_dwords);
|
memory_->TranslatePhysical<uint32_t*>(reader->ptr()),
|
||||||
|
size_dwords);
|
||||||
|
switch (shader_type) {
|
||||||
|
case ShaderType::kVertex:
|
||||||
|
active_vertex_shader_ = shader;
|
||||||
|
break;
|
||||||
|
case ShaderType::kPixel:
|
||||||
|
active_pixel_shader_ = shader;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert_unhandled_case(shader_type);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
reader->Advance(size_dwords);
|
reader->Advance(size_dwords);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ namespace xe {
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
|
|
||||||
class GraphicsSystem;
|
class GraphicsSystem;
|
||||||
|
class Shader;
|
||||||
|
|
||||||
struct SwapState {
|
struct SwapState {
|
||||||
// Lock must be held when changing data in this structure.
|
// Lock must be held when changing data in this structure.
|
||||||
|
@ -60,6 +61,9 @@ class CommandProcessor {
|
||||||
uint32_t counter() const { return counter_; }
|
uint32_t counter() const { return counter_; }
|
||||||
void increment_counter() { counter_++; }
|
void increment_counter() { counter_++; }
|
||||||
|
|
||||||
|
Shader* active_vertex_shader() const { return active_vertex_shader_; }
|
||||||
|
Shader* active_pixel_shader() const { return active_pixel_shader_; }
|
||||||
|
|
||||||
virtual bool Initialize(std::unique_ptr<xe::ui::GraphicsContext> context);
|
virtual bool Initialize(std::unique_ptr<xe::ui::GraphicsContext> context);
|
||||||
virtual void Shutdown();
|
virtual void Shutdown();
|
||||||
|
|
||||||
|
@ -160,9 +164,9 @@ class CommandProcessor {
|
||||||
bool ExecutePacketType3_INVALIDATE_STATE(RingbufferReader* reader,
|
bool ExecutePacketType3_INVALIDATE_STATE(RingbufferReader* reader,
|
||||||
uint32_t packet, uint32_t count);
|
uint32_t packet, uint32_t count);
|
||||||
|
|
||||||
virtual bool LoadShader(ShaderType shader_type, uint32_t guest_address,
|
virtual Shader* LoadShader(ShaderType shader_type, uint32_t guest_address,
|
||||||
const uint32_t* host_address,
|
const uint32_t* host_address,
|
||||||
uint32_t dword_count) = 0;
|
uint32_t dword_count) = 0;
|
||||||
|
|
||||||
virtual bool IssueDraw(PrimitiveType prim_type, uint32_t index_count,
|
virtual bool IssueDraw(PrimitiveType prim_type, uint32_t index_count,
|
||||||
IndexBufferInfo* index_buffer_info) = 0;
|
IndexBufferInfo* index_buffer_info) = 0;
|
||||||
|
@ -205,6 +209,9 @@ class CommandProcessor {
|
||||||
|
|
||||||
uint64_t bin_select_ = 0xFFFFFFFFull;
|
uint64_t bin_select_ = 0xFFFFFFFFull;
|
||||||
uint64_t bin_mask_ = 0xFFFFFFFFull;
|
uint64_t bin_mask_ = 0xFFFFFFFFull;
|
||||||
|
|
||||||
|
Shader* active_vertex_shader_ = nullptr;
|
||||||
|
Shader* active_pixel_shader_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gpu
|
} // namespace gpu
|
||||||
|
|
|
@ -463,10 +463,10 @@ void GL4CommandProcessor::PerformSwap(uint32_t frontbuffer_ptr,
|
||||||
texture_cache_.Scavenge();
|
texture_cache_.Scavenge();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GL4CommandProcessor::LoadShader(ShaderType shader_type,
|
Shader* GL4CommandProcessor::LoadShader(ShaderType shader_type,
|
||||||
uint32_t guest_address,
|
uint32_t guest_address,
|
||||||
const uint32_t* host_address,
|
const uint32_t* host_address,
|
||||||
uint32_t dword_count) {
|
uint32_t dword_count) {
|
||||||
// Hash the input memory and lookup the shader.
|
// Hash the input memory and lookup the shader.
|
||||||
GL4Shader* shader_ptr = nullptr;
|
GL4Shader* shader_ptr = nullptr;
|
||||||
uint64_t hash = XXH64(host_address, dword_count * sizeof(uint32_t), 0);
|
uint64_t hash = XXH64(host_address, dword_count * sizeof(uint32_t), 0);
|
||||||
|
@ -489,18 +489,7 @@ bool GL4CommandProcessor::LoadShader(ShaderType shader_type,
|
||||||
guest_address, dword_count * 4,
|
guest_address, dword_count * 4,
|
||||||
shader_ptr->ucode_disassembly().c_str());
|
shader_ptr->ucode_disassembly().c_str());
|
||||||
}
|
}
|
||||||
switch (shader_type) {
|
return shader_ptr;
|
||||||
case ShaderType::kVertex:
|
|
||||||
active_vertex_shader_ = shader_ptr;
|
|
||||||
break;
|
|
||||||
case ShaderType::kPixel:
|
|
||||||
active_pixel_shader_ = shader_ptr;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert_unhandled_case(shader_type);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GL4CommandProcessor::IssueDraw(PrimitiveType prim_type,
|
bool GL4CommandProcessor::IssueDraw(PrimitiveType prim_type,
|
||||||
|
@ -622,8 +611,8 @@ GL4CommandProcessor::UpdateStatus GL4CommandProcessor::UpdateShaders(
|
||||||
if (!dirty) {
|
if (!dirty) {
|
||||||
return UpdateStatus::kCompatible;
|
return UpdateStatus::kCompatible;
|
||||||
}
|
}
|
||||||
regs.vertex_shader = active_vertex_shader_;
|
regs.vertex_shader = static_cast<GL4Shader*>(active_vertex_shader_);
|
||||||
regs.pixel_shader = active_pixel_shader_;
|
regs.pixel_shader = static_cast<GL4Shader*>(active_pixel_shader_);
|
||||||
regs.prim_type = prim_type;
|
regs.prim_type = prim_type;
|
||||||
|
|
||||||
SCOPE_profile_cpu_f("gpu");
|
SCOPE_profile_cpu_f("gpu");
|
||||||
|
@ -632,30 +621,30 @@ GL4CommandProcessor::UpdateStatus GL4CommandProcessor::UpdateShaders(
|
||||||
|
|
||||||
xe_gpu_program_cntl_t program_cntl;
|
xe_gpu_program_cntl_t program_cntl;
|
||||||
program_cntl.dword_0 = regs.sq_program_cntl;
|
program_cntl.dword_0 = regs.sq_program_cntl;
|
||||||
if (!active_vertex_shader_->has_prepared()) {
|
if (!regs.vertex_shader->has_prepared()) {
|
||||||
if (!active_vertex_shader_->PrepareVertexShader(&shader_translator_,
|
if (!regs.vertex_shader->PrepareVertexShader(&shader_translator_,
|
||||||
program_cntl)) {
|
program_cntl)) {
|
||||||
XELOGE("Unable to prepare vertex shader");
|
XELOGE("Unable to prepare vertex shader");
|
||||||
return UpdateStatus::kError;
|
return UpdateStatus::kError;
|
||||||
}
|
}
|
||||||
} else if (!active_vertex_shader_->is_valid()) {
|
} else if (!regs.vertex_shader->is_valid()) {
|
||||||
XELOGE("Vertex shader invalid");
|
XELOGE("Vertex shader invalid");
|
||||||
return UpdateStatus::kError;
|
return UpdateStatus::kError;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!active_pixel_shader_->has_prepared()) {
|
if (!regs.pixel_shader->has_prepared()) {
|
||||||
if (!active_pixel_shader_->PreparePixelShader(&shader_translator_,
|
if (!regs.pixel_shader->PreparePixelShader(&shader_translator_,
|
||||||
program_cntl)) {
|
program_cntl)) {
|
||||||
XELOGE("Unable to prepare pixel shader");
|
XELOGE("Unable to prepare pixel shader");
|
||||||
return UpdateStatus::kError;
|
return UpdateStatus::kError;
|
||||||
}
|
}
|
||||||
} else if (!active_pixel_shader_->is_valid()) {
|
} else if (!regs.pixel_shader->is_valid()) {
|
||||||
XELOGE("Pixel shader invalid");
|
XELOGE("Pixel shader invalid");
|
||||||
return UpdateStatus::kError;
|
return UpdateStatus::kError;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint vertex_program = active_vertex_shader_->program();
|
GLuint vertex_program = regs.vertex_shader->program();
|
||||||
GLuint fragment_program = active_pixel_shader_->program();
|
GLuint fragment_program = regs.pixel_shader->program();
|
||||||
|
|
||||||
uint64_t key = (uint64_t(vertex_program) << 32) | fragment_program;
|
uint64_t key = (uint64_t(vertex_program) << 32) | fragment_program;
|
||||||
CachedPipeline* cached_pipeline = nullptr;
|
CachedPipeline* cached_pipeline = nullptr;
|
||||||
|
@ -707,7 +696,7 @@ GL4CommandProcessor::UpdateStatus GL4CommandProcessor::UpdateShaders(
|
||||||
cached_pipeline->handles.line_quad_list_pipeline = pipelines[4];
|
cached_pipeline->handles.line_quad_list_pipeline = pipelines[4];
|
||||||
|
|
||||||
// This can be set once, as the buffer never changes.
|
// This can be set once, as the buffer never changes.
|
||||||
glVertexArrayElementBuffer(active_vertex_shader_->vao(),
|
glVertexArrayElementBuffer(regs.vertex_shader->vao(),
|
||||||
scratch_buffer_.handle());
|
scratch_buffer_.handle());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -741,11 +730,11 @@ GL4CommandProcessor::UpdateStatus GL4CommandProcessor::UpdateShaders(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_batcher_.ReconfigurePipeline(active_vertex_shader_, active_pixel_shader_,
|
draw_batcher_.ReconfigurePipeline(regs.vertex_shader, regs.pixel_shader,
|
||||||
pipeline);
|
pipeline);
|
||||||
|
|
||||||
glBindProgramPipeline(pipeline);
|
glBindProgramPipeline(pipeline);
|
||||||
glBindVertexArray(active_vertex_shader_->vao());
|
glBindVertexArray(regs.vertex_shader->vao());
|
||||||
|
|
||||||
return UpdateStatus::kMismatch;
|
return UpdateStatus::kMismatch;
|
||||||
}
|
}
|
||||||
|
@ -1394,6 +1383,7 @@ GL4CommandProcessor::UpdateStatus GL4CommandProcessor::PopulateVertexBuffers() {
|
||||||
|
|
||||||
trace_writer_.WriteMemoryRead(fetch->address << 2, valid_range);
|
trace_writer_.WriteMemoryRead(fetch->address << 2, valid_range);
|
||||||
|
|
||||||
|
auto vertex_shader = static_cast<GL4Shader*>(active_vertex_shader_);
|
||||||
CircularBuffer::Allocation allocation;
|
CircularBuffer::Allocation allocation;
|
||||||
if (!scratch_buffer_.AcquireCached(fetch->address << 2, valid_range,
|
if (!scratch_buffer_.AcquireCached(fetch->address << 2, valid_range,
|
||||||
&allocation)) {
|
&allocation)) {
|
||||||
|
@ -1408,7 +1398,7 @@ GL4CommandProcessor::UpdateStatus GL4CommandProcessor::PopulateVertexBuffers() {
|
||||||
|
|
||||||
// TODO(benvanik): if we could find a way to avoid this, we could use
|
// TODO(benvanik): if we could find a way to avoid this, we could use
|
||||||
// multidraw without flushing.
|
// multidraw without flushing.
|
||||||
glVertexArrayVertexBuffer(active_vertex_shader_->vao(), buffer_index,
|
glVertexArrayVertexBuffer(vertex_shader->vao(), buffer_index,
|
||||||
scratch_buffer_.handle(), allocation.offset,
|
scratch_buffer_.handle(), allocation.offset,
|
||||||
desc.stride_words * 4);
|
desc.stride_words * 4);
|
||||||
|
|
||||||
|
@ -1416,7 +1406,7 @@ GL4CommandProcessor::UpdateStatus GL4CommandProcessor::PopulateVertexBuffers() {
|
||||||
} else {
|
} else {
|
||||||
// TODO(benvanik): if we could find a way to avoid this, we could use
|
// TODO(benvanik): if we could find a way to avoid this, we could use
|
||||||
// multidraw without flushing.
|
// multidraw without flushing.
|
||||||
glVertexArrayVertexBuffer(active_vertex_shader_->vao(), buffer_index,
|
glVertexArrayVertexBuffer(vertex_shader->vao(), buffer_index,
|
||||||
scratch_buffer_.handle(), allocation.offset,
|
scratch_buffer_.handle(), allocation.offset,
|
||||||
desc.stride_words * 4);
|
desc.stride_words * 4);
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,8 +49,6 @@ class GL4CommandProcessor : public CommandProcessor {
|
||||||
|
|
||||||
// HACK: for debugging; would be good to have this in a base type.
|
// HACK: for debugging; would be good to have this in a base type.
|
||||||
TextureCache* texture_cache() { return &texture_cache_; }
|
TextureCache* texture_cache() { return &texture_cache_; }
|
||||||
GL4Shader* active_vertex_shader() const { return active_vertex_shader_; }
|
|
||||||
GL4Shader* active_pixel_shader() const { return active_pixel_shader_; }
|
|
||||||
|
|
||||||
GLuint GetColorRenderTarget(uint32_t pitch, xenos::MsaaSamples samples,
|
GLuint GetColorRenderTarget(uint32_t pitch, xenos::MsaaSamples samples,
|
||||||
uint32_t base,
|
uint32_t base,
|
||||||
|
@ -111,8 +109,9 @@ class GL4CommandProcessor : public CommandProcessor {
|
||||||
void PerformSwap(uint32_t frontbuffer_ptr, uint32_t frontbuffer_width,
|
void PerformSwap(uint32_t frontbuffer_ptr, uint32_t frontbuffer_width,
|
||||||
uint32_t frontbuffer_height) override;
|
uint32_t frontbuffer_height) override;
|
||||||
|
|
||||||
bool LoadShader(ShaderType shader_type, uint32_t guest_address,
|
Shader* LoadShader(ShaderType shader_type, uint32_t guest_address,
|
||||||
const uint32_t* host_address, uint32_t dword_count) override;
|
const uint32_t* host_address,
|
||||||
|
uint32_t dword_count) override;
|
||||||
|
|
||||||
bool IssueDraw(PrimitiveType prim_type, uint32_t index_count,
|
bool IssueDraw(PrimitiveType prim_type, uint32_t index_count,
|
||||||
IndexBufferInfo* index_buffer_info) override;
|
IndexBufferInfo* index_buffer_info) override;
|
||||||
|
@ -135,8 +134,6 @@ class GL4CommandProcessor : public CommandProcessor {
|
||||||
GL4ShaderTranslator shader_translator_;
|
GL4ShaderTranslator shader_translator_;
|
||||||
std::vector<std::unique_ptr<GL4Shader>> all_shaders_;
|
std::vector<std::unique_ptr<GL4Shader>> all_shaders_;
|
||||||
std::unordered_map<uint64_t, GL4Shader*> shader_cache_;
|
std::unordered_map<uint64_t, GL4Shader*> shader_cache_;
|
||||||
GL4Shader* active_vertex_shader_ = nullptr;
|
|
||||||
GL4Shader* active_pixel_shader_ = nullptr;
|
|
||||||
CachedFramebuffer* active_framebuffer_ = nullptr;
|
CachedFramebuffer* active_framebuffer_ = nullptr;
|
||||||
GLuint last_framebuffer_texture_ = 0;
|
GLuint last_framebuffer_texture_ = 0;
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,97 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XENIA_GPU_TRACE_VIEWER_H_
|
||||||
|
#define XENIA_GPU_TRACE_VIEWER_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "xenia/emulator.h"
|
||||||
|
#include "xenia/gpu/shader.h"
|
||||||
|
#include "xenia/gpu/trace_player.h"
|
||||||
|
#include "xenia/gpu/trace_protocol.h"
|
||||||
|
#include "xenia/gpu/xenos.h"
|
||||||
|
#include "xenia/memory.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace ui {
|
||||||
|
class ImGuiDrawer;
|
||||||
|
class Loop;
|
||||||
|
class Window;
|
||||||
|
} // namespace ui
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace gpu {
|
||||||
|
|
||||||
|
struct SamplerInfo;
|
||||||
|
struct TextureInfo;
|
||||||
|
|
||||||
|
class TraceViewer {
|
||||||
|
public:
|
||||||
|
virtual ~TraceViewer();
|
||||||
|
|
||||||
|
bool Setup();
|
||||||
|
bool Load(std::wstring trace_file_path);
|
||||||
|
void Run();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
TraceViewer();
|
||||||
|
|
||||||
|
void DrawMultilineString(const std::string& str);
|
||||||
|
|
||||||
|
virtual uintptr_t GetColorRenderTarget(
|
||||||
|
uint32_t pitch, xenos::MsaaSamples samples, uint32_t base,
|
||||||
|
xenos::ColorRenderTargetFormat format) = 0;
|
||||||
|
virtual uintptr_t GetDepthRenderTarget(
|
||||||
|
uint32_t pitch, xenos::MsaaSamples samples, uint32_t base,
|
||||||
|
xenos::DepthRenderTargetFormat format) = 0;
|
||||||
|
virtual uintptr_t GetTextureEntry(const TextureInfo& texture_info,
|
||||||
|
const SamplerInfo& sampler_info) = 0;
|
||||||
|
|
||||||
|
std::unique_ptr<xe::ui::Loop> loop_;
|
||||||
|
std::unique_ptr<xe::ui::Window> window_;
|
||||||
|
std::unique_ptr<Emulator> emulator_;
|
||||||
|
Memory* memory_ = nullptr;
|
||||||
|
GraphicsSystem* graphics_system_ = nullptr;
|
||||||
|
std::unique_ptr<TracePlayer> player_;
|
||||||
|
|
||||||
|
std::unique_ptr<xe::ui::ImGuiDrawer> imgui_drawer_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum class ShaderDisplayType : int {
|
||||||
|
kUcode,
|
||||||
|
kTranslated,
|
||||||
|
kHostDisasm,
|
||||||
|
};
|
||||||
|
|
||||||
|
void DrawUI();
|
||||||
|
void DrawControllerUI();
|
||||||
|
void DrawPacketDisassemblerUI();
|
||||||
|
void DrawCommandListUI();
|
||||||
|
void DrawStateUI();
|
||||||
|
|
||||||
|
ShaderDisplayType DrawShaderTypeUI();
|
||||||
|
void DrawShaderUI(Shader* shader, ShaderDisplayType display_type);
|
||||||
|
|
||||||
|
void DrawBlendMode(uint32_t src_blend, uint32_t dest_blend,
|
||||||
|
uint32_t blend_op);
|
||||||
|
|
||||||
|
void DrawTextureInfo(const Shader::SamplerDesc& desc);
|
||||||
|
void DrawFailedTextureInfo(const Shader::SamplerDesc& desc,
|
||||||
|
const char* message);
|
||||||
|
|
||||||
|
void DrawVertexFetcher(Shader* shader, const Shader::BufferDesc& desc,
|
||||||
|
const xenos::xe_gpu_vertex_fetch_t* fetch);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace gpu
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
#endif // XENIA_GPU_TRACE_VIEWER_H_
|
Loading…
Reference in New Issue