diff options
-rw-r--r-- | src/video_core/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/video_core/rasterizer_interface.h | 61 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 269 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 162 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 1 |
5 files changed, 495 insertions, 1 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index df4368f52..e56253c4c 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -11,8 +11,11 @@ add_library(video_core STATIC gpu.h memory_manager.cpp memory_manager.h + rasterizer_interface.h renderer_base.cpp renderer_base.h + renderer_opengl/gl_rasterizer.cpp + renderer_opengl/gl_rasterizer.h renderer_opengl/gl_rasterizer_cache.cpp renderer_opengl/gl_rasterizer_cache.h renderer_opengl/gl_resource_manager.h diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h new file mode 100644 index 000000000..6c7bd0826 --- /dev/null +++ b/src/video_core/rasterizer_interface.h @@ -0,0 +1,61 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +struct ScreenInfo; + +namespace VideoCore { + +class RasterizerInterface { +public: + virtual ~RasterizerInterface() {} + + /// Draw the current batch of triangles + virtual void DrawTriangles() = 0; + + /// Notify rasterizer that the specified Maxwell register has been changed + virtual void NotifyMaxwellRegisterChanged(u32 id) = 0; + + /// Notify rasterizer that all caches should be flushed to 3DS memory + virtual void FlushAll() = 0; + + /// Notify rasterizer that any caches of the specified region should be flushed to 3DS memory + virtual void FlushRegion(PAddr addr, u32 size) = 0; + + /// Notify rasterizer that any caches of the specified region should be invalidated + virtual void InvalidateRegion(PAddr addr, u32 size) = 0; + + /// Notify rasterizer that any caches of the specified region should be flushed to 3DS memory + /// and invalidated + virtual void FlushAndInvalidateRegion(PAddr addr, u32 size) = 0; + + /// Attempt to use a faster method to perform a display transfer with is_texture_copy = 0 + virtual bool AccelerateDisplayTransfer(const void* config) { + return false; + } + + /// Attempt to use a faster method to perform a display transfer with is_texture_copy = 1 + virtual bool AccelerateTextureCopy(const void* config) { + return false; + } + + /// Attempt to use a faster method to fill a region + virtual bool AccelerateFill(const void* config) { + return false; + } + + /// Attempt to use a faster method to display the framebuffer to screen + virtual bool AccelerateDisplay(const void* config, PAddr framebuffer_addr, u32 pixel_stride, + ScreenInfo& screen_info) { + return false; + } + + virtual bool AccelerateDrawBatch(bool is_indexed) { + return false; + } +}; +} // namespace VideoCore diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp new file mode 100644 index 000000000..24cfff229 --- /dev/null +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -0,0 +1,269 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <memory> +#include <string> +#include <tuple> +#include <utility> +#include <glad/glad.h> +#include "common/alignment.h" +#include "common/assert.h" +#include "common/logging/log.h" +#include "common/math_util.h" +#include "common/microprofile.h" +#include "common/scope_exit.h" +#include "common/vector_math.h" +#include "core/settings.h" +#include "video_core/renderer_opengl/gl_rasterizer.h" +#include "video_core/renderer_opengl/gl_shader_gen.h" +#include "video_core/renderer_opengl/renderer_opengl.h" + +using PixelFormat = SurfaceParams::PixelFormat; +using SurfaceType = SurfaceParams::SurfaceType; + +MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Array Setup", MP_RGB(128, 128, 192)); +MICROPROFILE_DEFINE(OpenGL_VS, "OpenGL", "Vertex Shader Setup", MP_RGB(128, 128, 192)); +MICROPROFILE_DEFINE(OpenGL_FS, "OpenGL", "Fragment Shader Setup", MP_RGB(128, 128, 192)); +MICROPROFILE_DEFINE(OpenGL_Drawing, "OpenGL", "Drawing", MP_RGB(128, 128, 192)); +MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255)); +MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100)); + +enum class UniformBindings : GLuint { Common, VS, FS }; + +static void SetShaderUniformBlockBinding(GLuint shader, const char* name, UniformBindings binding, + size_t expected_size) { + GLuint ub_index = glGetUniformBlockIndex(shader, name); + if (ub_index != GL_INVALID_INDEX) { + GLint ub_size = 0; + glGetActiveUniformBlockiv(shader, ub_index, GL_UNIFORM_BLOCK_DATA_SIZE, &ub_size); + ASSERT_MSG(ub_size == expected_size, + "Uniform block size did not match! Got %d, expected %zu", + static_cast<int>(ub_size), expected_size); + glUniformBlockBinding(shader, ub_index, static_cast<GLuint>(binding)); + } +} + +static void SetShaderUniformBlockBindings(GLuint shader) { + SetShaderUniformBlockBinding(shader, "shader_data", UniformBindings::Common, + sizeof(RasterizerOpenGL::UniformData)); + SetShaderUniformBlockBinding(shader, "vs_config", UniformBindings::VS, + sizeof(RasterizerOpenGL::VSUniformData)); + SetShaderUniformBlockBinding(shader, "fs_config", UniformBindings::FS, + sizeof(RasterizerOpenGL::FSUniformData)); +} + +RasterizerOpenGL::RasterizerOpenGL() { + has_ARB_buffer_storage = false; + has_ARB_direct_state_access = false; + has_ARB_separate_shader_objects = false; + has_ARB_vertex_attrib_binding = false; + + GLint ext_num; + glGetIntegerv(GL_NUM_EXTENSIONS, &ext_num); + for (GLint i = 0; i < ext_num; i++) { + std::string extension{reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i))}; + + if (extension == "GL_ARB_buffer_storage") { + has_ARB_buffer_storage = true; + } else if (extension == "GL_ARB_direct_state_access") { + has_ARB_direct_state_access = true; + } else if (extension == "GL_ARB_separate_shader_objects") { + has_ARB_separate_shader_objects = true; + } else if (extension == "GL_ARB_vertex_attrib_binding") { + has_ARB_vertex_attrib_binding = true; + } + } + + // Clipping plane 0 is always enabled for PICA fixed clip plane z <= 0 + state.clip_distance[0] = true; + + // Generate VBO, VAO and UBO + vertex_buffer = OGLStreamBuffer::MakeBuffer(GLAD_GL_ARB_buffer_storage, GL_ARRAY_BUFFER); + vertex_buffer->Create(VERTEX_BUFFER_SIZE, VERTEX_BUFFER_SIZE / 2); + sw_vao.Create(); + uniform_buffer.Create(); + + state.draw.vertex_array = sw_vao.handle; + state.draw.vertex_buffer = vertex_buffer->GetHandle(); + state.draw.uniform_buffer = uniform_buffer.handle; + state.Apply(); + + glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformData), nullptr, GL_STATIC_DRAW); + glBindBufferBase(GL_UNIFORM_BUFFER, 0, uniform_buffer.handle); + + uniform_block_data.dirty = true; + + // Create render framebuffer + framebuffer.Create(); + + if (has_ARB_separate_shader_objects) { + hw_vao.Create(); + hw_vao_enabled_attributes.fill(false); + + stream_buffer = OGLStreamBuffer::MakeBuffer(has_ARB_buffer_storage, GL_ARRAY_BUFFER); + stream_buffer->Create(STREAM_BUFFER_SIZE, STREAM_BUFFER_SIZE / 2); + state.draw.vertex_buffer = stream_buffer->GetHandle(); + + pipeline.Create(); + vs_input_index_min = 0; + vs_input_index_max = 0; + state.draw.program_pipeline = pipeline.handle; + state.draw.shader_program = 0; + state.draw.vertex_array = hw_vao.handle; + state.Apply(); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, stream_buffer->GetHandle()); + + vs_uniform_buffer.Create(); + glBindBuffer(GL_UNIFORM_BUFFER, vs_uniform_buffer.handle); + glBufferData(GL_UNIFORM_BUFFER, sizeof(VSUniformData), nullptr, GL_STREAM_COPY); + glBindBufferBase(GL_UNIFORM_BUFFER, 1, vs_uniform_buffer.handle); + } else { + UNIMPLEMENTED(); + } + + accelerate_draw = AccelDraw::Disabled; + + glEnable(GL_BLEND); + + // Sync fixed function OpenGL state + SyncClipEnabled(); + SyncClipCoef(); + SyncCullMode(); + SyncBlendEnabled(); + SyncBlendFuncs(); + SyncBlendColor(); +} + +RasterizerOpenGL::~RasterizerOpenGL() { + if (stream_buffer != nullptr) { + state.draw.vertex_buffer = stream_buffer->GetHandle(); + state.Apply(); + stream_buffer->Release(); + } +} + +static constexpr std::array<GLenum, 4> vs_attrib_types{ + GL_BYTE, // VertexAttributeFormat::BYTE + GL_UNSIGNED_BYTE, // VertexAttributeFormat::UBYTE + GL_SHORT, // VertexAttributeFormat::SHORT + GL_FLOAT // VertexAttributeFormat::FLOAT +}; + +void RasterizerOpenGL::AnalyzeVertexArray(bool is_indexed) { + UNIMPLEMENTED(); +} + +void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) { + MICROPROFILE_SCOPE(OpenGL_VAO); + UNIMPLEMENTED(); +} + +void RasterizerOpenGL::SetupVertexShader(VSUniformData* ub_ptr, GLintptr buffer_offset) { + MICROPROFILE_SCOPE(OpenGL_VS); + UNIMPLEMENTED(); +} + +void RasterizerOpenGL::SetupFragmentShader(FSUniformData* ub_ptr, GLintptr buffer_offset) { + MICROPROFILE_SCOPE(OpenGL_FS); + UNIMPLEMENTED(); +} + +bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) { + if (!has_ARB_separate_shader_objects) { + UNIMPLEMENTED(); + return false; + } + + accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays; + DrawTriangles(); + + return true; +} + +void RasterizerOpenGL::DrawTriangles() { + MICROPROFILE_SCOPE(OpenGL_Drawing); + UNIMPLEMENTED(); +} + +void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 id) {} + +void RasterizerOpenGL::FlushAll() { + MICROPROFILE_SCOPE(OpenGL_CacheManagement); + res_cache.FlushAll(); +} + +void RasterizerOpenGL::FlushRegion(PAddr addr, u32 size) { + MICROPROFILE_SCOPE(OpenGL_CacheManagement); + res_cache.FlushRegion(addr, size); +} + +void RasterizerOpenGL::InvalidateRegion(PAddr addr, u32 size) { + MICROPROFILE_SCOPE(OpenGL_CacheManagement); + res_cache.InvalidateRegion(addr, size, nullptr); +} + +void RasterizerOpenGL::FlushAndInvalidateRegion(PAddr addr, u32 size) { + MICROPROFILE_SCOPE(OpenGL_CacheManagement); + res_cache.FlushRegion(addr, size); + res_cache.InvalidateRegion(addr, size, nullptr); +} + +bool RasterizerOpenGL::AccelerateDisplayTransfer(const void* config) { + MICROPROFILE_SCOPE(OpenGL_Blits); + UNIMPLEMENTED(); + return true; +} + +bool RasterizerOpenGL::AccelerateTextureCopy(const void* config) { + UNIMPLEMENTED(); + return true; +} + +bool RasterizerOpenGL::AccelerateFill(const void* config) { + UNIMPLEMENTED(); + return true; +} + +bool RasterizerOpenGL::AccelerateDisplay(const void* config, PAddr framebuffer_addr, + u32 pixel_stride, ScreenInfo& screen_info) { + UNIMPLEMENTED(); + return true; +} + +void RasterizerOpenGL::SetShader() { + UNIMPLEMENTED(); +} + +void RasterizerOpenGL::SyncClipEnabled() { + UNIMPLEMENTED(); +} + +void RasterizerOpenGL::SyncClipCoef() { + UNIMPLEMENTED(); +} + +void RasterizerOpenGL::SyncCullMode() { + UNIMPLEMENTED(); +} + +void RasterizerOpenGL::SyncDepthScale() { + UNIMPLEMENTED(); +} + +void RasterizerOpenGL::SyncDepthOffset() { + UNIMPLEMENTED(); +} + +void RasterizerOpenGL::SyncBlendEnabled() { + UNIMPLEMENTED(); +} + +void RasterizerOpenGL::SyncBlendFuncs() { + UNIMPLEMENTED(); +} + +void RasterizerOpenGL::SyncBlendColor() { + UNIMPLEMENTED(); +} diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h new file mode 100644 index 000000000..893fc530f --- /dev/null +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -0,0 +1,162 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> +#include <cstddef> +#include <cstring> +#include <memory> +#include <unordered_map> +#include <vector> +#include <glad/glad.h> +#include "common/bit_field.h" +#include "common/common_types.h" +#include "common/hash.h" +#include "common/vector_math.h" +#include "video_core/rasterizer_interface.h" +#include "video_core/renderer_opengl/gl_rasterizer_cache.h" +#include "video_core/renderer_opengl/gl_resource_manager.h" +#include "video_core/renderer_opengl/gl_shader_gen.h" +#include "video_core/renderer_opengl/gl_state.h" +#include "video_core/renderer_opengl/gl_stream_buffer.h" + +struct ScreenInfo; + +class RasterizerOpenGL : public VideoCore::RasterizerInterface { +public: + RasterizerOpenGL(); + ~RasterizerOpenGL() override; + + void DrawTriangles() override; + void NotifyMaxwellRegisterChanged(u32 id) override; + void FlushAll() override; + void FlushRegion(PAddr addr, u32 size) override; + void InvalidateRegion(PAddr addr, u32 size) override; + void FlushAndInvalidateRegion(PAddr addr, u32 size) override; + bool AccelerateDisplayTransfer(const void* config) override; + bool AccelerateTextureCopy(const void* config) override; + bool AccelerateFill(const void* config) override; + bool AccelerateDisplay(const void* config, PAddr framebuffer_addr, u32 pixel_stride, + ScreenInfo& screen_info) override; + bool AccelerateDrawBatch(bool is_indexed) override; + + struct VertexShader { + OGLShader shader; + }; + + struct FragmentShader { + OGLShader shader; + }; + + /// Uniform structure for the Uniform Buffer Object, all vectors must be 16-byte aligned + // NOTE: Always keep a vec4 at the end. The GL spec is not clear wether the alignment at + // the end of a uniform block is included in UNIFORM_BLOCK_DATA_SIZE or not. + // Not following that rule will cause problems on some AMD drivers. + struct UniformData {}; + + // static_assert( + // sizeof(UniformData) == 0x460, + // "The size of the UniformData structure has changed, update the structure in the shader"); + static_assert(sizeof(UniformData) < 16384, + "UniformData structure must be less than 16kb as per the OpenGL spec"); + + struct VSUniformData {}; + // static_assert( + // sizeof(VSUniformData) == 1856, + // "The size of the VSUniformData structure has changed, update the structure in the + // shader"); + static_assert(sizeof(VSUniformData) < 16384, + "VSUniformData structure must be less than 16kb as per the OpenGL spec"); + + struct FSUniformData {}; + // static_assert( + // sizeof(FSUniformData) == 1856, + // "The size of the FSUniformData structure has changed, update the structure in the + // shader"); + static_assert(sizeof(FSUniformData) < 16384, + "FSUniformData structure must be less than 16kb as per the OpenGL spec"); + +private: + struct SamplerInfo {}; + + /// Syncs the clip enabled status to match the guest state + void SyncClipEnabled(); + + /// Syncs the clip coefficients to match the guest state + void SyncClipCoef(); + + /// Sets the OpenGL shader in accordance with the current guest state + void SetShader(); + + /// Syncs the cull mode to match the guest state + void SyncCullMode(); + + /// Syncs the depth scale to match the guest state + void SyncDepthScale(); + + /// Syncs the depth offset to match the guest state + void SyncDepthOffset(); + + /// Syncs the blend enabled status to match the guest state + void SyncBlendEnabled(); + + /// Syncs the blend functions to match the guest state + void SyncBlendFuncs(); + + /// Syncs the blend color to match the guest state + void SyncBlendColor(); + + bool has_ARB_buffer_storage; + bool has_ARB_direct_state_access; + bool has_ARB_separate_shader_objects; + bool has_ARB_vertex_attrib_binding; + + OpenGLState state; + + RasterizerCacheOpenGL res_cache; + + struct { + UniformData data; + bool dirty; + } uniform_block_data = {}; + + OGLPipeline pipeline; + OGLVertexArray sw_vao; + OGLVertexArray hw_vao; + std::array<bool, 16> hw_vao_enabled_attributes; + + std::array<SamplerInfo, 3> texture_samplers; + static constexpr size_t VERTEX_BUFFER_SIZE = 128 * 1024 * 1024; + std::unique_ptr<OGLStreamBuffer> vertex_buffer; + OGLBuffer uniform_buffer; + OGLFramebuffer framebuffer; + + static constexpr size_t STREAM_BUFFER_SIZE = 4 * 1024 * 1024; + std::unique_ptr<OGLStreamBuffer> stream_buffer; + + GLint vs_input_index_min; + GLint vs_input_index_max; + GLsizeiptr vs_input_size; + + void AnalyzeVertexArray(bool is_indexed); + void SetupVertexArray(u8* array_ptr, GLintptr buffer_offset); + + OGLBuffer vs_uniform_buffer; + std::unordered_map<GLShader::MaxwellVSConfig, VertexShader*> vs_shader_map; + std::unordered_map<std::string, VertexShader> vs_shader_cache; + OGLShader vs_default_shader; + + void SetupVertexShader(VSUniformData* ub_ptr, GLintptr buffer_offset); + + OGLBuffer fs_uniform_buffer; + std::unordered_map<GLShader::MaxwellFSConfig, FragmentShader*> fs_shader_map; + std::unordered_map<std::string, FragmentShader> fs_shader_cache; + OGLShader fs_default_shader; + + void SetupFragmentShader(FSUniformData* ub_ptr, GLintptr buffer_offset); + + enum class AccelDraw { Disabled, Arrays, Indexed }; + AccelDraw accelerate_draw; +}; diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index e481139af..884637ca5 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -26,7 +26,6 @@ #include "core/settings.h" #include "video_core/renderer_opengl/gl_rasterizer_cache.h" #include "video_core/renderer_opengl/gl_state.h" -#include "video_core/texture/texture_decode.h" #include "video_core/utils.h" #include "video_core/video_core.h" |