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
|
||||
assert_true(start == 0);
|
||||
trace_writer_.WriteMemoryRead(CpuToGpu(addr), size_dwords * 4);
|
||||
LoadShader(shader_type, addr, memory_->TranslatePhysical<uint32_t*>(addr),
|
||||
size_dwords);
|
||||
auto shader =
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1095,8 +1107,20 @@ bool CommandProcessor::ExecutePacketType3_IM_LOAD_IMMEDIATE(
|
|||
uint32_t size_dwords = start_size & 0xFFFF; // dwords
|
||||
assert_true(start == 0);
|
||||
reader->CheckRead(size_dwords);
|
||||
LoadShader(shader_type, reader->ptr(),
|
||||
memory_->TranslatePhysical<uint32_t*>(reader->ptr()), size_dwords);
|
||||
auto shader = LoadShader(shader_type, reader->ptr(),
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace xe {
|
|||
namespace gpu {
|
||||
|
||||
class GraphicsSystem;
|
||||
class Shader;
|
||||
|
||||
struct SwapState {
|
||||
// Lock must be held when changing data in this structure.
|
||||
|
@ -60,6 +61,9 @@ class CommandProcessor {
|
|||
uint32_t counter() const { return 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 void Shutdown();
|
||||
|
||||
|
@ -160,9 +164,9 @@ class CommandProcessor {
|
|||
bool ExecutePacketType3_INVALIDATE_STATE(RingbufferReader* reader,
|
||||
uint32_t packet, uint32_t count);
|
||||
|
||||
virtual bool LoadShader(ShaderType shader_type, uint32_t guest_address,
|
||||
const uint32_t* host_address,
|
||||
uint32_t dword_count) = 0;
|
||||
virtual Shader* LoadShader(ShaderType shader_type, uint32_t guest_address,
|
||||
const uint32_t* host_address,
|
||||
uint32_t dword_count) = 0;
|
||||
|
||||
virtual bool IssueDraw(PrimitiveType prim_type, uint32_t index_count,
|
||||
IndexBufferInfo* index_buffer_info) = 0;
|
||||
|
@ -205,6 +209,9 @@ class CommandProcessor {
|
|||
|
||||
uint64_t bin_select_ = 0xFFFFFFFFull;
|
||||
uint64_t bin_mask_ = 0xFFFFFFFFull;
|
||||
|
||||
Shader* active_vertex_shader_ = nullptr;
|
||||
Shader* active_pixel_shader_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace gpu
|
||||
|
|
|
@ -463,10 +463,10 @@ void GL4CommandProcessor::PerformSwap(uint32_t frontbuffer_ptr,
|
|||
texture_cache_.Scavenge();
|
||||
}
|
||||
|
||||
bool GL4CommandProcessor::LoadShader(ShaderType shader_type,
|
||||
uint32_t guest_address,
|
||||
const uint32_t* host_address,
|
||||
uint32_t dword_count) {
|
||||
Shader* GL4CommandProcessor::LoadShader(ShaderType shader_type,
|
||||
uint32_t guest_address,
|
||||
const uint32_t* host_address,
|
||||
uint32_t dword_count) {
|
||||
// Hash the input memory and lookup the shader.
|
||||
GL4Shader* shader_ptr = nullptr;
|
||||
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,
|
||||
shader_ptr->ucode_disassembly().c_str());
|
||||
}
|
||||
switch (shader_type) {
|
||||
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;
|
||||
return shader_ptr;
|
||||
}
|
||||
|
||||
bool GL4CommandProcessor::IssueDraw(PrimitiveType prim_type,
|
||||
|
@ -622,8 +611,8 @@ GL4CommandProcessor::UpdateStatus GL4CommandProcessor::UpdateShaders(
|
|||
if (!dirty) {
|
||||
return UpdateStatus::kCompatible;
|
||||
}
|
||||
regs.vertex_shader = active_vertex_shader_;
|
||||
regs.pixel_shader = active_pixel_shader_;
|
||||
regs.vertex_shader = static_cast<GL4Shader*>(active_vertex_shader_);
|
||||
regs.pixel_shader = static_cast<GL4Shader*>(active_pixel_shader_);
|
||||
regs.prim_type = prim_type;
|
||||
|
||||
SCOPE_profile_cpu_f("gpu");
|
||||
|
@ -632,30 +621,30 @@ GL4CommandProcessor::UpdateStatus GL4CommandProcessor::UpdateShaders(
|
|||
|
||||
xe_gpu_program_cntl_t program_cntl;
|
||||
program_cntl.dword_0 = regs.sq_program_cntl;
|
||||
if (!active_vertex_shader_->has_prepared()) {
|
||||
if (!active_vertex_shader_->PrepareVertexShader(&shader_translator_,
|
||||
program_cntl)) {
|
||||
if (!regs.vertex_shader->has_prepared()) {
|
||||
if (!regs.vertex_shader->PrepareVertexShader(&shader_translator_,
|
||||
program_cntl)) {
|
||||
XELOGE("Unable to prepare vertex shader");
|
||||
return UpdateStatus::kError;
|
||||
}
|
||||
} else if (!active_vertex_shader_->is_valid()) {
|
||||
} else if (!regs.vertex_shader->is_valid()) {
|
||||
XELOGE("Vertex shader invalid");
|
||||
return UpdateStatus::kError;
|
||||
}
|
||||
|
||||
if (!active_pixel_shader_->has_prepared()) {
|
||||
if (!active_pixel_shader_->PreparePixelShader(&shader_translator_,
|
||||
program_cntl)) {
|
||||
if (!regs.pixel_shader->has_prepared()) {
|
||||
if (!regs.pixel_shader->PreparePixelShader(&shader_translator_,
|
||||
program_cntl)) {
|
||||
XELOGE("Unable to prepare pixel shader");
|
||||
return UpdateStatus::kError;
|
||||
}
|
||||
} else if (!active_pixel_shader_->is_valid()) {
|
||||
} else if (!regs.pixel_shader->is_valid()) {
|
||||
XELOGE("Pixel shader invalid");
|
||||
return UpdateStatus::kError;
|
||||
}
|
||||
|
||||
GLuint vertex_program = active_vertex_shader_->program();
|
||||
GLuint fragment_program = active_pixel_shader_->program();
|
||||
GLuint vertex_program = regs.vertex_shader->program();
|
||||
GLuint fragment_program = regs.pixel_shader->program();
|
||||
|
||||
uint64_t key = (uint64_t(vertex_program) << 32) | fragment_program;
|
||||
CachedPipeline* cached_pipeline = nullptr;
|
||||
|
@ -707,7 +696,7 @@ GL4CommandProcessor::UpdateStatus GL4CommandProcessor::UpdateShaders(
|
|||
cached_pipeline->handles.line_quad_list_pipeline = pipelines[4];
|
||||
|
||||
// This can be set once, as the buffer never changes.
|
||||
glVertexArrayElementBuffer(active_vertex_shader_->vao(),
|
||||
glVertexArrayElementBuffer(regs.vertex_shader->vao(),
|
||||
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);
|
||||
|
||||
glBindProgramPipeline(pipeline);
|
||||
glBindVertexArray(active_vertex_shader_->vao());
|
||||
glBindVertexArray(regs.vertex_shader->vao());
|
||||
|
||||
return UpdateStatus::kMismatch;
|
||||
}
|
||||
|
@ -1394,6 +1383,7 @@ GL4CommandProcessor::UpdateStatus GL4CommandProcessor::PopulateVertexBuffers() {
|
|||
|
||||
trace_writer_.WriteMemoryRead(fetch->address << 2, valid_range);
|
||||
|
||||
auto vertex_shader = static_cast<GL4Shader*>(active_vertex_shader_);
|
||||
CircularBuffer::Allocation allocation;
|
||||
if (!scratch_buffer_.AcquireCached(fetch->address << 2, valid_range,
|
||||
&allocation)) {
|
||||
|
@ -1408,7 +1398,7 @@ GL4CommandProcessor::UpdateStatus GL4CommandProcessor::PopulateVertexBuffers() {
|
|||
|
||||
// TODO(benvanik): if we could find a way to avoid this, we could use
|
||||
// multidraw without flushing.
|
||||
glVertexArrayVertexBuffer(active_vertex_shader_->vao(), buffer_index,
|
||||
glVertexArrayVertexBuffer(vertex_shader->vao(), buffer_index,
|
||||
scratch_buffer_.handle(), allocation.offset,
|
||||
desc.stride_words * 4);
|
||||
|
||||
|
@ -1416,7 +1406,7 @@ GL4CommandProcessor::UpdateStatus GL4CommandProcessor::PopulateVertexBuffers() {
|
|||
} else {
|
||||
// TODO(benvanik): if we could find a way to avoid this, we could use
|
||||
// multidraw without flushing.
|
||||
glVertexArrayVertexBuffer(active_vertex_shader_->vao(), buffer_index,
|
||||
glVertexArrayVertexBuffer(vertex_shader->vao(), buffer_index,
|
||||
scratch_buffer_.handle(), allocation.offset,
|
||||
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.
|
||||
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,
|
||||
uint32_t base,
|
||||
|
@ -111,8 +109,9 @@ class GL4CommandProcessor : public CommandProcessor {
|
|||
void PerformSwap(uint32_t frontbuffer_ptr, uint32_t frontbuffer_width,
|
||||
uint32_t frontbuffer_height) override;
|
||||
|
||||
bool LoadShader(ShaderType shader_type, uint32_t guest_address,
|
||||
const uint32_t* host_address, uint32_t dword_count) 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;
|
||||
|
@ -135,8 +134,6 @@ class GL4CommandProcessor : public CommandProcessor {
|
|||
GL4ShaderTranslator shader_translator_;
|
||||
std::vector<std::unique_ptr<GL4Shader>> all_shaders_;
|
||||
std::unordered_map<uint64_t, GL4Shader*> shader_cache_;
|
||||
GL4Shader* active_vertex_shader_ = nullptr;
|
||||
GL4Shader* active_pixel_shader_ = nullptr;
|
||||
CachedFramebuffer* active_framebuffer_ = nullptr;
|
||||
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