Playing with buffers.

This commit is contained in:
Ben Vanik 2014-12-25 01:39:10 -08:00
parent f438ae1bfd
commit 39541aaaac
13 changed files with 351 additions and 93 deletions

View File

@ -0,0 +1,84 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <xenia/gpu/gl4/circular_buffer.h>
#include <poly/assert.h>
#include <poly/math.h>
#include <xenia/gpu/gpu-private.h>
namespace xe {
namespace gpu {
namespace gl4 {
extern "C" GLEWContext* glewGetContext();
extern "C" WGLEWContext* wglewGetContext();
CircularBuffer::CircularBuffer(size_t capacity)
: capacity_(capacity),
write_head_(0),
buffer_(0),
gpu_base_(0),
host_base_(nullptr) {}
CircularBuffer::~CircularBuffer() {
glUnmapNamedBuffer(buffer_);
glDeleteBuffers(1, &buffer_);
}
bool CircularBuffer::Initialize() {
glCreateBuffers(1, &buffer_);
glNamedBufferStorage(buffer_, capacity_, nullptr,
GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT);
host_base_ = reinterpret_cast<uint8_t*>(glMapNamedBufferRange(
buffer_, 0, capacity_, GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
GL_MAP_UNSYNCHRONIZED_BIT |
GL_MAP_PERSISTENT_BIT));
assert_not_null(host_base_);
if (!host_base_) {
return false;
}
glMakeNamedBufferResidentNV(buffer_, GL_WRITE_ONLY);
glGetNamedBufferParameterui64vNV(buffer_, GL_BUFFER_GPU_ADDRESS_NV,
&gpu_base_);
return true;
}
CircularBuffer::Allocation CircularBuffer::Acquire(size_t length) {
// Addresses must always be % 256.
length = poly::round_up(length, 256);
assert_true(length <= capacity_, "Request too large");
if (write_head_ + length > capacity_) {
// Flush and wait.
WaitUntilClean();
}
Allocation allocation;
allocation.host_ptr = host_base_ + write_head_;
allocation.gpu_ptr = gpu_base_ + write_head_;
allocation.length = length;
write_head_ += length;
return allocation;
}
void CircularBuffer::Commit(Allocation allocation) {
glFlushMappedNamedBufferRange(buffer_, allocation.gpu_ptr - gpu_base_,
allocation.length);
}
void CircularBuffer::WaitUntilClean() {
glFinish();
write_head_ = 0;
}
} // namespace gl4
} // namespace gpu
} // namespace xe

View File

@ -0,0 +1,51 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_GL4_CIRCULAR_BUFFER_H_
#define XENIA_GPU_GL4_CIRCULAR_BUFFER_H_
#include <xenia/gpu/gl4/gl_context.h>
namespace xe {
namespace gpu {
namespace gl4 {
// TODO(benvanik): uh, make this circular.
// TODO(benvanik): fences to prevent this from ever flushing.
class CircularBuffer {
public:
CircularBuffer(size_t capacity);
~CircularBuffer();
struct Allocation {
void* host_ptr;
GLuint64 gpu_ptr;
size_t length;
};
bool Initialize();
Allocation Acquire(size_t length);
void Commit(Allocation allocation);
void WaitUntilClean();
private:
size_t capacity_;
uintptr_t write_head_;
GLuint buffer_;
GLuint64 gpu_base_;
uint8_t* host_base_;
};
} // namespace gl4
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_GL4_CIRCULAR_BUFFER_H_

View File

@ -1,11 +1,11 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <xenia/gpu/gl4/command_processor.h>
@ -33,6 +33,11 @@ extern "C" GLEWContext* glewGetContext();
const GLuint kAnyTarget = UINT_MAX;
// All uncached vertex/index data goes here. If it fills up we need to sync
// with the GPU, so this should be large enough to prevent that in a normal
// frame.
const size_t kScratchBufferCapacity = 64 * 1024 * 1024;
CommandProcessor::CommandProcessor(GL4GraphicsSystem* graphics_system)
: memory_(graphics_system->memory()),
membase_(graphics_system->memory()->membase()),
@ -52,7 +57,8 @@ CommandProcessor::CommandProcessor(GL4GraphicsSystem* graphics_system)
bin_mask_(0xFFFFFFFFull),
active_vertex_shader_(nullptr),
active_pixel_shader_(nullptr),
active_framebuffer_(nullptr) {
active_framebuffer_(nullptr),
scratch_buffer_(kScratchBufferCapacity) {
std::memset(&draw_command_, 0, sizeof(draw_command_));
LARGE_INTEGER perf_counter;
QueryPerformanceCounter(&perf_counter);
@ -144,6 +150,14 @@ bool CommandProcessor::SetupGL() {
glNamedBufferStorage(uniform_data_buffer_, 16 * 1024, nullptr,
GL_MAP_WRITE_BIT | GL_DYNAMIC_STORAGE_BIT);
// Circular buffer holding scratch vertex/index data.
glEnableClientState(GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV);
glEnableClientState(GL_ELEMENT_ARRAY_UNIFIED_NV);
if (!scratch_buffer_.Initialize()) {
PLOGE("Unable to initialize scratch buffer");
return false;
}
return true;
}
@ -919,7 +933,7 @@ bool CommandProcessor::ExecutePacketType3_DRAW_INDX(RingbufferReader* reader,
// Indexed draw.
draw_command_.index_buffer.address = membase_ + index_base;
draw_command_.index_buffer.size = index_size;
draw_command_.index_buffer.endianess = index_endianness;
draw_command_.index_buffer.endianness = index_endianness;
draw_command_.index_buffer.format =
index_32bit ? IndexFormat::kInt32 : IndexFormat::kInt16;
} else if (src_sel == 0x2) {
@ -1120,6 +1134,7 @@ void CommandProcessor::PrepareDraw(DrawCommand* draw_command) {
bool CommandProcessor::IssueDraw(DrawCommand* draw_command) {
SCOPE_profile_cpu_f("gpu");
auto& regs = *register_file_;
auto& cmd = *draw_command;
auto enable_mode =
static_cast<ModeControl>(regs[XE_GPU_REG_RB_MODECONTROL].u32 & 0x7);
if (enable_mode == ModeControl::kIgnore) {
@ -1154,16 +1169,31 @@ bool CommandProcessor::IssueDraw(DrawCommand* draw_command) {
// return false;
//}
// if (!PopulateIndexBuffer(draw_command)) {
// PLOGE("Unable to setup index buffer");
// return false;
//}
// if (!PopulateVertexBuffers(draw_command)) {
// XELOGE("Unable to setup vertex buffers");
// return false;
//}
if (!PopulateIndexBuffer(draw_command)) {
PLOGE("Unable to setup index buffer");
return false;
}
if (!PopulateVertexBuffers(draw_command)) {
XELOGE("Unable to setup vertex buffers");
return false;
}
// TODO(benvanik): draw.
if (cmd.index_buffer.address) {
// Indexed draw.
// PopulateIndexBuffer has our element array setup.
//size_t element_size = cmd.index_buffer.format == IndexFormat::kInt32
// ? sizeof(uint32_t)
// : sizeof(uint16_t);
//glDrawElementsBaseVertex(
// prim_type, cmd.index_count,
// cmd.index_buffer.format == IndexFormat::kInt32 ? GL_UNSIGNED_INT
// : GL_UNSIGNED_SHORT,
// reinterpret_cast<void*>(cmd.start_index * element_size),
// cmd.base_vertex);
} else {
// Auto draw.
//glDrawArrays(prim_type, cmd.start_index, cmd.index_count);
}
return true;
}
@ -1567,6 +1597,103 @@ bool CommandProcessor::UpdateRenderTargets(DrawCommand* draw_command) {
return true;
}
bool CommandProcessor::PopulateIndexBuffer(DrawCommand* draw_command) {
SCOPE_profile_cpu_f("gpu");
auto& cmd = *draw_command;
auto& info = cmd.index_buffer;
if (!cmd.index_count || !info.address) {
// No index buffer or auto draw.
return true;
}
assert_true(info.endianness == Endian::k8in16 ||
info.endianness == Endian::k8in32);
auto allocation = scratch_buffer_.Acquire(cmd.index_count *
(info.format == IndexFormat::kInt32
? sizeof(uint32_t)
: sizeof(uint16_t)));
if (info.format == IndexFormat::kInt32) {
poly::copy_and_swap_32_aligned(
reinterpret_cast<uint32_t*>(allocation.host_ptr),
reinterpret_cast<const uint32_t*>(cmd.index_buffer.address),
cmd.index_count);
} else {
poly::copy_and_swap_16_aligned(
reinterpret_cast<uint16_t*>(allocation.host_ptr),
reinterpret_cast<const uint16_t*>(cmd.index_buffer.address),
cmd.index_count);
}
glBufferAddressRangeNV(GL_ELEMENT_ARRAY_ADDRESS_NV, 0, allocation.gpu_ptr,
allocation.length);
scratch_buffer_.Commit(std::move(allocation));
return true;
}
bool CommandProcessor::PopulateVertexBuffers(DrawCommand* draw_command) {
SCOPE_profile_cpu_f("gpu");
auto& regs = *register_file_;
auto& cmd = *draw_command;
if (!cmd.vertex_shader) {
// No vertex shader, no-op.
return true;
}
const auto& buffer_inputs = cmd.vertex_shader->buffer_inputs();
// glBindVertexArray(vertex_array);
for (size_t n = 0; n < buffer_inputs.count; n++) {
const auto& desc = buffer_inputs.descs[n];
int r = XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 + (desc.fetch_slot / 3) * 6;
auto group = reinterpret_cast<xe_gpu_fetch_group_t*>(&regs.values[r]);
xe_gpu_vertex_fetch_t* fetch = nullptr;
switch (desc.fetch_slot % 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_not_null(fetch);
assert_true(fetch->type == 0x3); // must be of type vertex
// TODO(benvanik): some games have type 2, which is texture - maybe
// fetch_slot wrong?
assert_not_zero(fetch->size);
auto allocation = scratch_buffer_.Acquire(fetch->size * sizeof(uint32_t));
// Copy and byte swap the entire buffer.
// We could be smart about this to save GPU bandwidth by building a CRC
// as we copy and only if it differs from the previous value committing
// it (and if it matches just discard and reuse).
poly::copy_and_swap_32_aligned(
reinterpret_cast<uint32_t*>(allocation.host_ptr),
reinterpret_cast<const uint32_t*>(membase_ + (fetch->address << 2)),
fetch->size);
/*glBufferAddressRangeNV(GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV,
desc.input_index,
allocation.gpu_ptr, allocation.length);*/
// Flush buffer before we draw.
scratch_buffer_.Commit(std::move(allocation));
}
return true;
}
bool CommandProcessor::IssueCopy(DrawCommand* draw_command) {
auto& regs = *register_file_;

View File

@ -1,11 +1,11 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_GL4_COMMAND_PROCESSOR_H_
#define XENIA_GPU_GL4_COMMAND_PROCESSOR_H_
@ -17,6 +17,7 @@
#include <unordered_map>
#include <vector>
#include <xenia/gpu/gl4/circular_buffer.h>
#include <xenia/gpu/gl4/gl_context.h>
#include <xenia/gpu/gl4/gl4_shader.h>
#include <xenia/gpu/register_file.h>
@ -54,19 +55,10 @@ struct DrawCommand {
struct {
const uint8_t* address;
size_t size;
xenos::Endian endianess;
xenos::Endian endianness;
xenos::IndexFormat format;
} index_buffer;
// Vertex buffers.
struct {
uint32_t input_index;
// VertexBufferResource* buffer;
uint32_t stride;
uint32_t offset;
} vertex_buffers[96];
size_t vertex_buffer_count;
// Texture samplers.
struct SamplerInput {
uint32_t input_index;
@ -196,8 +188,8 @@ class CommandProcessor {
bool IssueDraw(DrawCommand* draw_command);
bool UpdateState(DrawCommand* draw_command);
bool UpdateRenderTargets(DrawCommand* draw_command);
// bool PopulateIndexBuffer(DrawCommand* draw_command);
// bool PopulateVertexBuffers(DrawCommand* draw_command);
bool PopulateIndexBuffer(DrawCommand* draw_command);
bool PopulateVertexBuffers(DrawCommand* draw_command);
bool IssueCopy(DrawCommand* draw_command);
CachedFramebuffer* GetFramebuffer(GLuint color_targets[4],
@ -248,6 +240,8 @@ class CommandProcessor {
std::vector<CachedColorRenderTarget> cached_color_render_targets_;
std::vector<CachedDepthRenderTarget> cached_depth_render_targets_;
CircularBuffer scratch_buffer_;
DrawCommand draw_command_;
};

View File

@ -1,11 +1,11 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <xenia/gpu/gl4/gl4_graphics_system.h>

View File

@ -1,11 +1,11 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_GL4_GL4_GRAPHICS_SYSTEM_H_
#define XENIA_GPU_GL4_GL4_GRAPHICS_SYSTEM_H_

View File

@ -1,11 +1,11 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <xenia/gpu/gl4/gl4_shader.h>

View File

@ -1,11 +1,11 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_GL4_GL4_SHADER_H_
#define XENIA_GPU_GL4_GL4_SHADER_H_

View File

@ -1,11 +1,11 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <xenia/gpu/gl4/gl_context.h>

View File

@ -1,11 +1,11 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_GL4_GL_CONTEXT_H_
#define XENIA_GPU_GL4_GL_CONTEXT_H_

View File

@ -1,6 +1,8 @@
# Copyright 2014 Ben Vanik. All Rights Reserved.
{
'sources': [
'circular_buffer.cc',
'circular_buffer.h',
'command_processor.cc',
'command_processor.h',
'gl4_gpu-private.h',

View File

@ -1,11 +1,11 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <xenia/gpu/gl4/wgl_control.h>

View File

@ -1,11 +1,11 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_GL4_WGL_CONTROL_H_
#define XENIA_GPU_GL4_WGL_CONTROL_H_