GPU: Eliminate temporary buffer when reading back

This commit is contained in:
Connor McLaughlin 2019-11-14 17:16:59 +10:00
parent 3998b9684e
commit 9ea7a8418c
11 changed files with 39 additions and 50 deletions

View file

@ -1,5 +1,6 @@
#include "gpu.h" #include "gpu.h"
#include "YBaseLib/Log.h" #include "YBaseLib/Log.h"
#include "common/heap_array.h"
#include "common/state_wrapper.h" #include "common/state_wrapper.h"
#include "dma.h" #include "dma.h"
#include "host_interface.h" #include "host_interface.h"
@ -127,16 +128,16 @@ bool GPU::DoState(StateWrapper& sw)
if (sw.IsReading()) if (sw.IsReading())
{ {
std::vector<u16> vram; // Still need a temporary here.
sw.Do(&vram); HeapArray<u16, VRAM_WIDTH * VRAM_HEIGHT> temp;
UpdateVRAM(0, 0, VRAM_WIDTH, VRAM_HEIGHT, vram.data()); sw.DoBytes(temp.data(), VRAM_WIDTH * VRAM_HEIGHT * sizeof(u16));
UpdateVRAM(0, 0, VRAM_WIDTH, VRAM_HEIGHT, temp.data());
UpdateDisplay(); UpdateDisplay();
} }
else else
{ {
std::vector<u16> vram(VRAM_WIDTH * VRAM_HEIGHT); ReadVRAM(0, 0, VRAM_WIDTH, VRAM_HEIGHT);
ReadVRAM(0, 0, VRAM_WIDTH, VRAM_HEIGHT, vram.data()); sw.DoBytes(m_vram_ptr, VRAM_WIDTH * VRAM_HEIGHT * sizeof(u16));
sw.Do(&vram);
} }
return !sw.HasError(); return !sw.HasError();
@ -693,7 +694,7 @@ void GPU::HandleGetGPUInfoCommand(u32 value)
void GPU::UpdateDisplay() {} void GPU::UpdateDisplay() {}
void GPU::ReadVRAM(u32 x, u32 y, u32 width, u32 height, void* buffer) {} void GPU::ReadVRAM(u32 x, u32 y, u32 width, u32 height) {}
void GPU::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) {} void GPU::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) {}

View file

@ -288,7 +288,7 @@ protected:
void HandleGetGPUInfoCommand(u32 value); void HandleGetGPUInfoCommand(u32 value);
// Rendering in the backend // Rendering in the backend
virtual void ReadVRAM(u32 x, u32 y, u32 width, u32 height, void* buffer); virtual void ReadVRAM(u32 x, u32 y, u32 width, u32 height);
virtual void FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color); virtual void FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color);
virtual void UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data); virtual void UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data);
virtual void CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height); virtual void CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height);
@ -303,6 +303,9 @@ protected:
InterruptController* m_interrupt_controller = nullptr; InterruptController* m_interrupt_controller = nullptr;
Timers* m_timers = nullptr; Timers* m_timers = nullptr;
// Pointer to VRAM, used for reads/writes. In the hardware backends, this is the shadow buffer.
u16* m_vram_ptr = nullptr;
union GPUSTAT union GPUSTAT
{ {
u32 bits; u32 bits;

View file

@ -330,14 +330,24 @@ bool GPU::HandleCopyRectangleVRAMToCPUCommand(const u32*& command_ptr, u32 comma
// all rendering should be done first... // all rendering should be done first...
FlushRender(); FlushRender();
// TODO: A better way of doing this.. // TODO: A better way of doing this.. get rid of the m_GPUREAD_buffer.
std::vector<u32> temp(num_words); ReadVRAM(src_x, src_y, width, height);
ReadVRAM(src_x, src_y, width, height, temp.data()); for (u32 row = 0; row < height;)
for (const u32 bits : temp) {
m_GPUREAD_buffer.push_back(bits); const u32 row_offset = ((src_y + row++) % VRAM_HEIGHT) * VRAM_WIDTH;
for (u32 col = 0; col < width;)
{
// TODO: Handle unaligned reads...
const u32 col_offset1 = row_offset + ((src_x + col++) % VRAM_WIDTH);
const u32 col_offset2 = row_offset + ((src_x + col++) % VRAM_WIDTH);
m_GPUREAD_buffer.push_back(ZeroExtend32(m_vram_ptr[col_offset1]) | (ZeroExtend32(m_vram_ptr[col_offset2]) << 16));
}
}
if (m_system->GetSettings().debugging.dump_vram_to_cpu_copies) if (m_system->GetSettings().debugging.dump_vram_to_cpu_copies)
{ {
std::vector<u32> temp;
std::copy(m_GPUREAD_buffer.begin(), m_GPUREAD_buffer.end(), std::back_inserter(temp));
DumpVRAMToFile(SmallString::FromFormat("vram_to_cpu_copy_%u.png", s_vram_to_cpu_dump_id++), width, height, DumpVRAMToFile(SmallString::FromFormat("vram_to_cpu_copy_%u.png", s_vram_to_cpu_dump_id++), width, height,
sizeof(u16) * width, temp.data(), true); sizeof(u16) * width, temp.data(), true);
} }

View file

@ -8,7 +8,10 @@
#include <sstream> #include <sstream>
Log_SetChannel(GPU_HW); Log_SetChannel(GPU_HW);
GPU_HW::GPU_HW() = default; GPU_HW::GPU_HW() : GPU()
{
m_vram_ptr = m_vram_shadow.data();
}
GPU_HW::~GPU_HW() = default; GPU_HW::~GPU_HW() = default;
@ -209,22 +212,6 @@ GPU_HW::BatchPrimitive GPU_HW::GetPrimitiveForCommand(RenderCommand rc)
return BatchPrimitive::Triangles; return BatchPrimitive::Triangles;
} }
void GPU_HW::ReadVRAM(u32 x, u32 y, u32 width, u32 height, void* buffer)
{
u8* out_ptr = static_cast<u8*>(buffer);
for (u32 row = 0; row < height; row++)
{
const u32 row_offset = ((y + row) % VRAM_HEIGHT) * VRAM_WIDTH;
for (u32 col = 0; col < width; col++)
{
const u32 col_offset = row_offset + ((x + col) % VRAM_WIDTH);
std::memcpy(out_ptr, &m_vram_shadow[col_offset], sizeof(u16));
out_ptr += sizeof(u16);
}
}
}
void GPU_HW::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) void GPU_HW::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color)
{ {
m_vram_dirty_rect.Include(Common::Rectangle<u32>::FromExtents(x, y, width, height)); m_vram_dirty_rect.Include(Common::Rectangle<u32>::FromExtents(x, y, width, height));

View file

@ -127,7 +127,6 @@ protected:
bool IsFlushed() const { return m_batch_current_vertex_ptr == m_batch_start_vertex_ptr; } bool IsFlushed() const { return m_batch_current_vertex_ptr == m_batch_start_vertex_ptr; }
void ReadVRAM(u32 x, u32 y, u32 width, u32 height, void* buffer) override;
void FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) override; void FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) override;
void UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data) override; void UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data) override;
void CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) override; void CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) override;

View file

@ -584,7 +584,7 @@ void GPU_HW_D3D11::UpdateDisplay()
} }
} }
void GPU_HW_D3D11::ReadVRAM(u32 x, u32 y, u32 width, u32 height, void* buffer) void GPU_HW_D3D11::ReadVRAM(u32 x, u32 y, u32 width, u32 height)
{ {
// Get bounds with wrap-around handled. // Get bounds with wrap-around handled.
const Common::Rectangle<u32> copy_rect = GetVRAMTransferBounds(x, y, width, height); const Common::Rectangle<u32> copy_rect = GetVRAMTransferBounds(x, y, width, height);
@ -614,9 +614,6 @@ void GPU_HW_D3D11::ReadVRAM(u32 x, u32 y, u32 width, u32 height, void* buffer)
} }
RestoreGraphicsAPIState(); RestoreGraphicsAPIState();
// Feed the shadow buffer back to the output.
GPU_HW::ReadVRAM(x, y, width, height, buffer);
} }
void GPU_HW_D3D11::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) void GPU_HW_D3D11::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color)

View file

@ -28,7 +28,7 @@ public:
protected: protected:
void UpdateDisplay() override; void UpdateDisplay() override;
void ReadVRAM(u32 x, u32 y, u32 width, u32 height, void* buffer) override; void ReadVRAM(u32 x, u32 y, u32 width, u32 height) override;
void FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) override; void FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) override;
void UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data) override; void UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data) override;
void CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) override; void CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) override;

View file

@ -526,7 +526,7 @@ void GPU_HW_OpenGL::UpdateDisplay()
} }
} }
void GPU_HW_OpenGL::ReadVRAM(u32 x, u32 y, u32 width, u32 height, void* buffer) void GPU_HW_OpenGL::ReadVRAM(u32 x, u32 y, u32 width, u32 height)
{ {
// Get bounds with wrap-around handled. // Get bounds with wrap-around handled.
const Common::Rectangle<u32> copy_rect = GetVRAMTransferBounds(x, y, width, height); const Common::Rectangle<u32> copy_rect = GetVRAMTransferBounds(x, y, width, height);
@ -554,9 +554,6 @@ void GPU_HW_OpenGL::ReadVRAM(u32 x, u32 y, u32 width, u32 height, void* buffer)
glPixelStorei(GL_PACK_ALIGNMENT, 4); glPixelStorei(GL_PACK_ALIGNMENT, 4);
glPixelStorei(GL_PACK_ROW_LENGTH, 0); glPixelStorei(GL_PACK_ROW_LENGTH, 0);
RestoreGraphicsAPIState(); RestoreGraphicsAPIState();
// Feed the shadow buffer back to the output.
GPU_HW::ReadVRAM(x, y, width, height, buffer);
} }
void GPU_HW_OpenGL::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) void GPU_HW_OpenGL::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color)

View file

@ -24,7 +24,7 @@ public:
protected: protected:
void UpdateDisplay() override; void UpdateDisplay() override;
void ReadVRAM(u32 x, u32 y, u32 width, u32 height, void* buffer) override; void ReadVRAM(u32 x, u32 y, u32 width, u32 height) override;
void FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) override; void FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) override;
void UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data) override; void UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data) override;
void CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) override; void CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) override;

View file

@ -10,6 +10,7 @@ Log_SetChannel(GPU_SW);
GPU_SW::GPU_SW() GPU_SW::GPU_SW()
{ {
m_vram.fill(0); m_vram.fill(0);
m_vram_ptr = m_vram.data();
} }
GPU_SW::~GPU_SW() GPU_SW::~GPU_SW()
@ -37,15 +38,9 @@ void GPU_SW::Reset()
m_vram.fill(0); m_vram.fill(0);
} }
void GPU_SW::ReadVRAM(u32 x, u32 y, u32 width, u32 height, void* buffer) void GPU_SW::ReadVRAM(u32 x, u32 y, u32 width, u32 height)
{ {
u16* buffer_ptr = static_cast<u16*>(buffer); // No need to do anything - pointer is already up to date.
for (u32 yoffs = 0; yoffs < height; yoffs++)
{
u16* src_ptr = GetPixelPtr(x, y + yoffs);
std::copy_n(src_ptr, width, buffer_ptr);
buffer_ptr += width;
}
} }
void GPU_SW::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) void GPU_SW::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color)

View file

@ -34,7 +34,7 @@ protected:
u8 texcoord_x, texcoord_y; u8 texcoord_x, texcoord_y;
}; };
void ReadVRAM(u32 x, u32 y, u32 width, u32 height, void* buffer) override; void ReadVRAM(u32 x, u32 y, u32 width, u32 height) override;
void FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) override; void FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color) override;
void UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data) override; void UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data) override;
void CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) override; void CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) override;