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

View file

@ -288,7 +288,7 @@ protected:
void HandleGetGPUInfoCommand(u32 value);
// 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 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);
@ -303,6 +303,9 @@ protected:
InterruptController* m_interrupt_controller = 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
{
u32 bits;

View file

@ -330,14 +330,24 @@ bool GPU::HandleCopyRectangleVRAMToCPUCommand(const u32*& command_ptr, u32 comma
// all rendering should be done first...
FlushRender();
// TODO: A better way of doing this..
std::vector<u32> temp(num_words);
ReadVRAM(src_x, src_y, width, height, temp.data());
for (const u32 bits : temp)
m_GPUREAD_buffer.push_back(bits);
// TODO: A better way of doing this.. get rid of the m_GPUREAD_buffer.
ReadVRAM(src_x, src_y, width, height);
for (u32 row = 0; row < height;)
{
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)
{
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,
sizeof(u16) * width, temp.data(), true);
}

View file

@ -8,7 +8,10 @@
#include <sstream>
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;
@ -209,22 +212,6 @@ GPU_HW::BatchPrimitive GPU_HW::GetPrimitiveForCommand(RenderCommand rc)
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)
{
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; }
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 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;

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.
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();
// 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)

View file

@ -28,7 +28,7 @@ public:
protected:
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 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;

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.
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_ROW_LENGTH, 0);
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)

View file

@ -24,7 +24,7 @@ public:
protected:
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 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;

View file

@ -10,6 +10,7 @@ Log_SetChannel(GPU_SW);
GPU_SW::GPU_SW()
{
m_vram.fill(0);
m_vram_ptr = m_vram.data();
}
GPU_SW::~GPU_SW()
@ -37,15 +38,9 @@ void GPU_SW::Reset()
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);
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;
}
// No need to do anything - pointer is already up to date.
}
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;
};
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 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;