xenia/src/xenia/gpu/gl4/command_processor.h
2015-09-06 18:07:52 -07:00

382 lines
13 KiB
C++

/**
******************************************************************************
* 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_
#include <atomic>
#include <cstring>
#include <functional>
#include <memory>
#include <mutex>
#include <queue>
#include <string>
#include <unordered_map>
#include <vector>
#include "xenia/base/threading.h"
#include "xenia/gpu/gl4/draw_batcher.h"
#include "xenia/gpu/gl4/gl4_shader.h"
#include "xenia/gpu/gl4/gl4_shader_translator.h"
#include "xenia/gpu/gl4/texture_cache.h"
#include "xenia/gpu/register_file.h"
#include "xenia/gpu/tracing.h"
#include "xenia/gpu/xenos.h"
#include "xenia/kernel/xthread.h"
#include "xenia/memory.h"
#include "xenia/ui/gl/circular_buffer.h"
#include "xenia/ui/gl/gl_context.h"
namespace xe {
namespace kernel {
class XHostThread;
} // namespace kernel
} // namespace xe
namespace xe {
namespace gpu {
namespace gl4 {
class GL4GraphicsSystem;
struct SwapState {
// Lock must be held when changing data in this structure.
std::mutex mutex;
// Dimensions of the framebuffer textures. Should match window size.
uint32_t width = 0;
uint32_t height = 0;
// Current front buffer, being drawn to the screen.
GLuint front_buffer_texture = 0;
// Current back buffer, being updated by the CP.
GLuint back_buffer_texture = 0;
// Whether the back buffer is dirty and a swap is pending.
bool pending = false;
};
enum class SwapMode {
kNormal,
kIgnored,
};
class CommandProcessor {
public:
explicit CommandProcessor(GL4GraphicsSystem* graphics_system);
~CommandProcessor();
uint32_t counter() const { return counter_; }
void increment_counter() { counter_++; }
bool Initialize(std::unique_ptr<xe::ui::GraphicsContext> context);
void Shutdown();
void CallInThread(std::function<void()> fn);
void ClearCaches();
SwapState& swap_state() { return swap_state_; }
void set_swap_mode(SwapMode swap_mode) { swap_mode_ = swap_mode; }
void IssueSwap(uint32_t frontbuffer_ptr, uint32_t frontbuffer_width,
uint32_t frontbuffer_height);
void set_swap_request_handler(std::function<void()> fn) {
swap_request_handler_ = fn;
}
void RequestFrameTrace(const std::wstring& root_path);
void BeginTracing(const std::wstring& root_path);
void EndTracing();
void InitializeRingBuffer(uint32_t ptr, uint32_t page_count);
void EnableReadPointerWriteBack(uint32_t ptr, uint32_t block_size);
void UpdateWritePointer(uint32_t value);
void ExecutePacket(uint32_t ptr, uint32_t count);
// 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,
xenos::ColorRenderTargetFormat format);
GLuint GetDepthRenderTarget(uint32_t pitch, xenos::MsaaSamples samples,
uint32_t base,
xenos::DepthRenderTargetFormat format);
private:
class RingbufferReader;
enum class UpdateStatus {
kCompatible,
kMismatch,
kError,
};
struct CachedFramebuffer {
GLuint color_targets[4];
GLuint depth_target;
GLuint framebuffer;
};
struct CachedColorRenderTarget {
uint32_t base;
uint32_t width;
uint32_t height;
xenos::ColorRenderTargetFormat format;
GLuint texture;
};
struct CachedDepthRenderTarget {
uint32_t base;
uint32_t width;
uint32_t height;
xenos::DepthRenderTargetFormat format;
GLuint texture;
};
struct CachedPipeline {
CachedPipeline();
~CachedPipeline();
GLuint vertex_program;
GLuint fragment_program;
struct {
GLuint default_pipeline;
GLuint point_list_pipeline;
GLuint rect_list_pipeline;
GLuint quad_list_pipeline;
GLuint line_quad_list_pipeline;
// TODO(benvanik): others with geometry shaders.
} handles;
};
void WorkerThreadMain();
bool SetupGL();
void ShutdownGL();
GLuint CreateGeometryProgram(const std::string& source);
void WriteRegister(uint32_t index, uint32_t value);
void MakeCoherent();
void PrepareForWait();
void ReturnFromWait();
void ExecutePrimaryBuffer(uint32_t start_index, uint32_t end_index);
void ExecuteIndirectBuffer(uint32_t ptr, uint32_t length);
bool ExecutePacket(RingbufferReader* reader);
bool ExecutePacketType0(RingbufferReader* reader, uint32_t packet);
bool ExecutePacketType1(RingbufferReader* reader, uint32_t packet);
bool ExecutePacketType2(RingbufferReader* reader, uint32_t packet);
bool ExecutePacketType3(RingbufferReader* reader, uint32_t packet);
bool ExecutePacketType3_ME_INIT(RingbufferReader* reader, uint32_t packet,
uint32_t count);
bool ExecutePacketType3_NOP(RingbufferReader* reader, uint32_t packet,
uint32_t count);
bool ExecutePacketType3_INTERRUPT(RingbufferReader* reader, uint32_t packet,
uint32_t count);
bool ExecutePacketType3_XE_SWAP(RingbufferReader* reader, uint32_t packet,
uint32_t count);
bool ExecutePacketType3_INDIRECT_BUFFER(RingbufferReader* reader,
uint32_t packet, uint32_t count);
bool ExecutePacketType3_WAIT_REG_MEM(RingbufferReader* reader,
uint32_t packet, uint32_t count);
bool ExecutePacketType3_REG_RMW(RingbufferReader* reader, uint32_t packet,
uint32_t count);
bool ExecutePacketType3_COND_WRITE(RingbufferReader* reader, uint32_t packet,
uint32_t count);
bool ExecutePacketType3_EVENT_WRITE(RingbufferReader* reader, uint32_t packet,
uint32_t count);
bool ExecutePacketType3_EVENT_WRITE_SHD(RingbufferReader* reader,
uint32_t packet, uint32_t count);
bool ExecutePacketType3_EVENT_WRITE_EXT(RingbufferReader* reader,
uint32_t packet, uint32_t count);
bool ExecutePacketType3_DRAW_INDX(RingbufferReader* reader, uint32_t packet,
uint32_t count);
bool ExecutePacketType3_DRAW_INDX_2(RingbufferReader* reader, uint32_t packet,
uint32_t count);
bool ExecutePacketType3_SET_CONSTANT(RingbufferReader* reader,
uint32_t packet, uint32_t count);
bool ExecutePacketType3_SET_CONSTANT2(RingbufferReader* reader,
uint32_t packet, uint32_t count);
bool ExecutePacketType3_LOAD_ALU_CONSTANT(RingbufferReader* reader,
uint32_t packet, uint32_t count);
bool ExecutePacketType3_SET_SHADER_CONSTANTS(RingbufferReader* reader,
uint32_t packet, uint32_t count);
bool ExecutePacketType3_IM_LOAD(RingbufferReader* reader, uint32_t packet,
uint32_t count);
bool ExecutePacketType3_IM_LOAD_IMMEDIATE(RingbufferReader* reader,
uint32_t packet, uint32_t count);
bool ExecutePacketType3_INVALIDATE_STATE(RingbufferReader* reader,
uint32_t packet, uint32_t count);
bool LoadShader(ShaderType shader_type, uint32_t guest_address,
const uint32_t* host_address, uint32_t dword_count);
bool IssueDraw();
UpdateStatus UpdateShaders(PrimitiveType prim_type);
UpdateStatus UpdateRenderTargets();
UpdateStatus UpdateState();
UpdateStatus UpdateViewportState();
UpdateStatus UpdateRasterizerState();
UpdateStatus UpdateBlendState();
UpdateStatus UpdateDepthStencilState();
UpdateStatus PopulateIndexBuffer();
UpdateStatus PopulateVertexBuffers();
UpdateStatus PopulateSamplers();
UpdateStatus PopulateSampler(const Shader::SamplerDesc& desc);
bool IssueCopy();
CachedFramebuffer* GetFramebuffer(GLuint color_targets[4],
GLuint depth_target);
Memory* memory_;
GL4GraphicsSystem* graphics_system_;
RegisterFile* register_file_;
TraceWriter trace_writer_;
enum class TraceState {
kDisabled,
kStreaming,
kSingleFrame,
};
TraceState trace_state_;
std::wstring trace_frame_path_;
std::atomic<bool> worker_running_;
kernel::object_ref<kernel::XHostThread> worker_thread_;
std::unique_ptr<xe::ui::GraphicsContext> context_;
SwapMode swap_mode_;
SwapState swap_state_;
std::function<void()> swap_request_handler_;
std::queue<std::function<void()>> pending_fns_;
uint32_t counter_;
uint32_t primary_buffer_ptr_;
uint32_t primary_buffer_size_;
uint32_t read_ptr_index_;
uint32_t read_ptr_update_freq_;
uint32_t read_ptr_writeback_ptr_;
std::unique_ptr<xe::threading::Event> write_ptr_index_event_;
std::atomic<uint32_t> write_ptr_index_;
uint64_t bin_select_;
uint64_t bin_mask_;
GL4ShaderTranslator shader_translator_;
std::vector<std::unique_ptr<GL4Shader>> all_shaders_;
std::unordered_map<uint64_t, GL4Shader*> shader_cache_;
GL4Shader* active_vertex_shader_;
GL4Shader* active_pixel_shader_;
CachedFramebuffer* active_framebuffer_;
GLuint last_framebuffer_texture_;
std::vector<CachedFramebuffer> cached_framebuffers_;
std::vector<CachedColorRenderTarget> cached_color_render_targets_;
std::vector<CachedDepthRenderTarget> cached_depth_render_targets_;
std::vector<std::unique_ptr<CachedPipeline>> all_pipelines_;
std::unordered_map<uint64_t, CachedPipeline*> cached_pipelines_;
GLuint point_list_geometry_program_;
GLuint rect_list_geometry_program_;
GLuint quad_list_geometry_program_;
GLuint line_quad_list_geometry_program_;
struct {
xenos::IndexFormat format;
xenos::Endian endianness;
uint32_t count;
uint32_t guest_base;
size_t length;
} index_buffer_info_;
uint32_t draw_index_count_;
TextureCache texture_cache_;
DrawBatcher draw_batcher_;
xe::ui::gl::CircularBuffer scratch_buffer_;
private:
bool SetShadowRegister(uint32_t* dest, uint32_t register_name);
bool SetShadowRegister(float* dest, uint32_t register_name);
struct UpdateRenderTargetsRegisters {
uint32_t rb_modecontrol;
uint32_t rb_surface_info;
uint32_t rb_color_info;
uint32_t rb_color1_info;
uint32_t rb_color2_info;
uint32_t rb_color3_info;
uint32_t rb_color_mask;
uint32_t rb_depthcontrol;
uint32_t rb_stencilrefmask;
uint32_t rb_depth_info;
UpdateRenderTargetsRegisters() { Reset(); }
void Reset() { std::memset(this, 0, sizeof(*this)); }
} update_render_targets_regs_;
struct UpdateViewportStateRegisters {
// uint32_t pa_cl_clip_cntl;
uint32_t rb_surface_info;
uint32_t pa_cl_vte_cntl;
uint32_t pa_su_sc_mode_cntl;
uint32_t pa_sc_window_offset;
uint32_t pa_sc_window_scissor_tl;
uint32_t pa_sc_window_scissor_br;
float pa_cl_vport_xoffset;
float pa_cl_vport_yoffset;
float pa_cl_vport_zoffset;
float pa_cl_vport_xscale;
float pa_cl_vport_yscale;
float pa_cl_vport_zscale;
UpdateViewportStateRegisters() { Reset(); }
void Reset() { std::memset(this, 0, sizeof(*this)); }
} update_viewport_state_regs_;
struct UpdateRasterizerStateRegisters {
uint32_t pa_su_sc_mode_cntl;
uint32_t pa_sc_screen_scissor_tl;
uint32_t pa_sc_screen_scissor_br;
uint32_t multi_prim_ib_reset_index;
UpdateRasterizerStateRegisters() { Reset(); }
void Reset() { std::memset(this, 0, sizeof(*this)); }
} update_rasterizer_state_regs_;
struct UpdateBlendStateRegisters {
uint32_t rb_blendcontrol[4];
float rb_blend_rgba[4];
UpdateBlendStateRegisters() { Reset(); }
void Reset() { std::memset(this, 0, sizeof(*this)); }
} update_blend_state_regs_;
struct UpdateDepthStencilStateRegisters {
uint32_t rb_depthcontrol;
uint32_t rb_stencilrefmask;
UpdateDepthStencilStateRegisters() { Reset(); }
void Reset() { std::memset(this, 0, sizeof(*this)); }
} update_depth_stencil_state_regs_;
struct UpdateShadersRegisters {
PrimitiveType prim_type;
uint32_t pa_su_sc_mode_cntl;
uint32_t sq_program_cntl;
GL4Shader* vertex_shader;
GL4Shader* pixel_shader;
UpdateShadersRegisters() { Reset(); }
void Reset() {
sq_program_cntl = 0;
vertex_shader = pixel_shader = nullptr;
}
} update_shaders_regs_;
};
} // namespace gl4
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_GL4_COMMAND_PROCESSOR_H_