diff --git a/src/xenia/gpu/gl4/circular_buffer.cc b/src/xenia/gpu/gl4/circular_buffer.cc new file mode 100644 index 000000000..a7d456c5a --- /dev/null +++ b/src/xenia/gpu/gl4/circular_buffer.cc @@ -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 + +#include +#include +#include + +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(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 diff --git a/src/xenia/gpu/gl4/circular_buffer.h b/src/xenia/gpu/gl4/circular_buffer.h new file mode 100644 index 000000000..2ef75853f --- /dev/null +++ b/src/xenia/gpu/gl4/circular_buffer.h @@ -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 + +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_ diff --git a/src/xenia/gpu/gl4/command_processor.cc b/src/xenia/gpu/gl4/command_processor.cc index 4f6fa56f8..69995d351 100644 --- a/src/xenia/gpu/gl4/command_processor.cc +++ b/src/xenia/gpu/gl4/command_processor.cc @@ -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 @@ -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(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(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(allocation.host_ptr), + reinterpret_cast(cmd.index_buffer.address), + cmd.index_count); + } else { + poly::copy_and_swap_16_aligned( + reinterpret_cast(allocation.host_ptr), + reinterpret_cast(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(®s.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(allocation.host_ptr), + reinterpret_cast(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_; diff --git a/src/xenia/gpu/gl4/command_processor.h b/src/xenia/gpu/gl4/command_processor.h index 2f57bd9ac..242325699 100644 --- a/src/xenia/gpu/gl4/command_processor.h +++ b/src/xenia/gpu/gl4/command_processor.h @@ -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 #include +#include #include #include #include @@ -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 cached_color_render_targets_; std::vector cached_depth_render_targets_; + CircularBuffer scratch_buffer_; + DrawCommand draw_command_; }; diff --git a/src/xenia/gpu/gl4/gl4_graphics_system.cc b/src/xenia/gpu/gl4/gl4_graphics_system.cc index 563a987c2..c61d4a6fa 100644 --- a/src/xenia/gpu/gl4/gl4_graphics_system.cc +++ b/src/xenia/gpu/gl4/gl4_graphics_system.cc @@ -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 diff --git a/src/xenia/gpu/gl4/gl4_graphics_system.h b/src/xenia/gpu/gl4/gl4_graphics_system.h index 5f53fbdaf..17e33f84c 100644 --- a/src/xenia/gpu/gl4/gl4_graphics_system.h +++ b/src/xenia/gpu/gl4/gl4_graphics_system.h @@ -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_ diff --git a/src/xenia/gpu/gl4/gl4_shader.cc b/src/xenia/gpu/gl4/gl4_shader.cc index a2f0dd5a2..d4861f1e2 100644 --- a/src/xenia/gpu/gl4/gl4_shader.cc +++ b/src/xenia/gpu/gl4/gl4_shader.cc @@ -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 diff --git a/src/xenia/gpu/gl4/gl4_shader.h b/src/xenia/gpu/gl4/gl4_shader.h index d33fc9239..079307e7a 100644 --- a/src/xenia/gpu/gl4/gl4_shader.h +++ b/src/xenia/gpu/gl4/gl4_shader.h @@ -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_ diff --git a/src/xenia/gpu/gl4/gl_context.cc b/src/xenia/gpu/gl4/gl_context.cc index bdfbced7a..3f4f48a01 100644 --- a/src/xenia/gpu/gl4/gl_context.cc +++ b/src/xenia/gpu/gl4/gl_context.cc @@ -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 diff --git a/src/xenia/gpu/gl4/gl_context.h b/src/xenia/gpu/gl4/gl_context.h index e6a9e93e7..68386b773 100644 --- a/src/xenia/gpu/gl4/gl_context.h +++ b/src/xenia/gpu/gl4/gl_context.h @@ -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_ diff --git a/src/xenia/gpu/gl4/sources.gypi b/src/xenia/gpu/gl4/sources.gypi index 0b8673696..1bba6e3ba 100644 --- a/src/xenia/gpu/gl4/sources.gypi +++ b/src/xenia/gpu/gl4/sources.gypi @@ -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', diff --git a/src/xenia/gpu/gl4/wgl_control.cc b/src/xenia/gpu/gl4/wgl_control.cc index bfd503b60..5571a1784 100644 --- a/src/xenia/gpu/gl4/wgl_control.cc +++ b/src/xenia/gpu/gl4/wgl_control.cc @@ -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 diff --git a/src/xenia/gpu/gl4/wgl_control.h b/src/xenia/gpu/gl4/wgl_control.h index 4c2f2d64d..f180a6eb3 100644 --- a/src/xenia/gpu/gl4/wgl_control.h +++ b/src/xenia/gpu/gl4/wgl_control.h @@ -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_