Browse Source
Merge pull request #254 from bunnei/port-citra-renderer
Merge pull request #254 from bunnei/port-citra-renderer
Port Citra OpenGL rasterizer codence_cpp
committed by
GitHub
22 changed files with 24260 additions and 1265 deletions
-
2externals/glad/Readme.md
-
4externals/glad/include/KHR/khrplatform.h
-
13761externals/glad/include/glad/glad.h
-
8750externals/glad/src/glad.c
-
11src/video_core/CMakeLists.txt
-
61src/video_core/rasterizer_interface.h
-
269src/video_core/renderer_opengl/gl_rasterizer.cpp
-
162src/video_core/renderer_opengl/gl_rasterizer.h
-
1361src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
-
350src/video_core/renderer_opengl/gl_rasterizer_cache.h
-
85src/video_core/renderer_opengl/gl_resource_manager.h
-
58src/video_core/renderer_opengl/gl_shader_decompiler.cpp
-
27src/video_core/renderer_opengl/gl_shader_decompiler.h
-
20src/video_core/renderer_opengl/gl_shader_gen.cpp
-
66src/video_core/renderer_opengl/gl_shader_gen.h
-
78src/video_core/renderer_opengl/gl_shader_util.cpp
-
6src/video_core/renderer_opengl/gl_shader_util.h
-
125src/video_core/renderer_opengl/gl_state.cpp
-
33src/video_core/renderer_opengl/gl_state.h
-
182src/video_core/renderer_opengl/gl_stream_buffer.cpp
-
34src/video_core/renderer_opengl/gl_stream_buffer.h
-
2src/video_core/renderer_opengl/renderer_opengl.cpp
@ -1,5 +1,5 @@ |
|||||
These files were generated by the [glad](https://github.com/Dav1dde/glad) OpenGL loader generator and have been checked in as-is. You can re-generate them using glad with the following command: |
These files were generated by the [glad](https://github.com/Dav1dde/glad) OpenGL loader generator and have been checked in as-is. You can re-generate them using glad with the following command: |
||||
|
|
||||
``` |
``` |
||||
python -m glad --profile core --out-path glad/ --api gl=3.3,gles=3.0 |
|
||||
|
python -m glad --profile core --out-path glad/ --api gl=3.3 --generator=c |
||||
``` |
``` |
||||
13761
externals/glad/include/glad/glad.h
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
8750
externals/glad/src/glad.c
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -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 |
||||
@ -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(); |
||||
|
} |
||||
@ -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; |
||||
|
}; |
||||
1361
src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,350 @@ |
|||||
|
// Copyright 2015 Citra Emulator Project |
||||
|
// Licensed under GPLv2 or any later version |
||||
|
// Refer to the license.txt file included. |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <array> |
||||
|
#include <memory> |
||||
|
#include <set> |
||||
|
#include <tuple> |
||||
|
#ifdef __GNUC__ |
||||
|
#pragma GCC diagnostic push |
||||
|
#pragma GCC diagnostic ignored "-Wunused-local-typedefs" |
||||
|
#endif |
||||
|
#include <boost/icl/interval_map.hpp> |
||||
|
#include <boost/icl/interval_set.hpp> |
||||
|
#ifdef __GNUC__ |
||||
|
#pragma GCC diagnostic pop |
||||
|
#endif |
||||
|
#include <glad/glad.h> |
||||
|
#include "common/assert.h" |
||||
|
#include "common/common_funcs.h" |
||||
|
#include "common/common_types.h" |
||||
|
#include "common/math_util.h" |
||||
|
#include "video_core/renderer_opengl/gl_resource_manager.h" |
||||
|
|
||||
|
struct CachedSurface; |
||||
|
using Surface = std::shared_ptr<CachedSurface>; |
||||
|
using SurfaceSet = std::set<Surface>; |
||||
|
|
||||
|
using SurfaceRegions = boost::icl::interval_set<PAddr>; |
||||
|
using SurfaceMap = boost::icl::interval_map<PAddr, Surface>; |
||||
|
using SurfaceCache = boost::icl::interval_map<PAddr, SurfaceSet>; |
||||
|
|
||||
|
using SurfaceInterval = SurfaceCache::interval_type; |
||||
|
static_assert(std::is_same<SurfaceRegions::interval_type, SurfaceCache::interval_type>() && |
||||
|
std::is_same<SurfaceMap::interval_type, SurfaceCache::interval_type>(), |
||||
|
"incorrect interval types"); |
||||
|
|
||||
|
using SurfaceRect_Tuple = std::tuple<Surface, MathUtil::Rectangle<u32>>; |
||||
|
using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, MathUtil::Rectangle<u32>>; |
||||
|
|
||||
|
using PageMap = boost::icl::interval_map<u32, int>; |
||||
|
|
||||
|
enum class ScaleMatch { |
||||
|
Exact, // only accept same res scale |
||||
|
Upscale, // only allow higher scale than params |
||||
|
Ignore // accept every scaled res |
||||
|
}; |
||||
|
|
||||
|
struct SurfaceParams { |
||||
|
enum class PixelFormat { |
||||
|
// First 5 formats are shared between textures and color buffers |
||||
|
RGBA8 = 0, |
||||
|
RGB8 = 1, |
||||
|
RGB5A1 = 2, |
||||
|
RGB565 = 3, |
||||
|
RGBA4 = 4, |
||||
|
|
||||
|
// Texture-only formats |
||||
|
IA8 = 5, |
||||
|
RG8 = 6, |
||||
|
I8 = 7, |
||||
|
A8 = 8, |
||||
|
IA4 = 9, |
||||
|
I4 = 10, |
||||
|
A4 = 11, |
||||
|
ETC1 = 12, |
||||
|
ETC1A4 = 13, |
||||
|
|
||||
|
// Depth buffer-only formats |
||||
|
D16 = 14, |
||||
|
// gap |
||||
|
D24 = 16, |
||||
|
D24S8 = 17, |
||||
|
|
||||
|
Invalid = 255, |
||||
|
}; |
||||
|
|
||||
|
enum class SurfaceType { |
||||
|
Color = 0, |
||||
|
Texture = 1, |
||||
|
Depth = 2, |
||||
|
DepthStencil = 3, |
||||
|
Fill = 4, |
||||
|
Invalid = 5 |
||||
|
}; |
||||
|
|
||||
|
static constexpr unsigned int GetFormatBpp(PixelFormat format) { |
||||
|
constexpr std::array<unsigned int, 18> bpp_table = { |
||||
|
32, // RGBA8 |
||||
|
24, // RGB8 |
||||
|
16, // RGB5A1 |
||||
|
16, // RGB565 |
||||
|
16, // RGBA4 |
||||
|
16, // IA8 |
||||
|
16, // RG8 |
||||
|
8, // I8 |
||||
|
8, // A8 |
||||
|
8, // IA4 |
||||
|
4, // I4 |
||||
|
4, // A4 |
||||
|
4, // ETC1 |
||||
|
8, // ETC1A4 |
||||
|
16, // D16 |
||||
|
0, |
||||
|
24, // D24 |
||||
|
32, // D24S8 |
||||
|
}; |
||||
|
|
||||
|
assert(static_cast<size_t>(format) < bpp_table.size()); |
||||
|
return bpp_table[static_cast<size_t>(format)]; |
||||
|
} |
||||
|
unsigned int GetFormatBpp() const { |
||||
|
return GetFormatBpp(pixel_format); |
||||
|
} |
||||
|
|
||||
|
static bool CheckFormatsBlittable(PixelFormat pixel_format_a, PixelFormat pixel_format_b) { |
||||
|
SurfaceType a_type = GetFormatType(pixel_format_a); |
||||
|
SurfaceType b_type = GetFormatType(pixel_format_b); |
||||
|
|
||||
|
if ((a_type == SurfaceType::Color || a_type == SurfaceType::Texture) && |
||||
|
(b_type == SurfaceType::Color || b_type == SurfaceType::Texture)) { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
if (a_type == SurfaceType::Depth && b_type == SurfaceType::Depth) { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
if (a_type == SurfaceType::DepthStencil && b_type == SurfaceType::DepthStencil) { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
static constexpr SurfaceType GetFormatType(PixelFormat pixel_format) { |
||||
|
if ((unsigned int)pixel_format < 5) { |
||||
|
return SurfaceType::Color; |
||||
|
} |
||||
|
|
||||
|
if ((unsigned int)pixel_format < 14) { |
||||
|
return SurfaceType::Texture; |
||||
|
} |
||||
|
|
||||
|
if (pixel_format == PixelFormat::D16 || pixel_format == PixelFormat::D24) { |
||||
|
return SurfaceType::Depth; |
||||
|
} |
||||
|
|
||||
|
if (pixel_format == PixelFormat::D24S8) { |
||||
|
return SurfaceType::DepthStencil; |
||||
|
} |
||||
|
|
||||
|
return SurfaceType::Invalid; |
||||
|
} |
||||
|
|
||||
|
/// Update the params "size", "end" and "type" from the already set "addr", "width", "height" |
||||
|
/// and "pixel_format" |
||||
|
void UpdateParams() { |
||||
|
if (stride == 0) { |
||||
|
stride = width; |
||||
|
} |
||||
|
type = GetFormatType(pixel_format); |
||||
|
size = !is_tiled ? BytesInPixels(stride * (height - 1) + width) |
||||
|
: BytesInPixels(stride * 8 * (height / 8 - 1) + width * 8); |
||||
|
end = addr + size; |
||||
|
} |
||||
|
|
||||
|
SurfaceInterval GetInterval() const { |
||||
|
return SurfaceInterval::right_open(addr, end); |
||||
|
} |
||||
|
|
||||
|
// Returns the outer rectangle containing "interval" |
||||
|
SurfaceParams FromInterval(SurfaceInterval interval) const; |
||||
|
|
||||
|
SurfaceInterval GetSubRectInterval(MathUtil::Rectangle<u32> unscaled_rect) const; |
||||
|
|
||||
|
// Returns the region of the biggest valid rectange within interval |
||||
|
SurfaceInterval GetCopyableInterval(const Surface& src_surface) const; |
||||
|
|
||||
|
u32 GetScaledWidth() const { |
||||
|
return width * res_scale; |
||||
|
} |
||||
|
|
||||
|
u32 GetScaledHeight() const { |
||||
|
return height * res_scale; |
||||
|
} |
||||
|
|
||||
|
MathUtil::Rectangle<u32> GetRect() const { |
||||
|
return {0, height, width, 0}; |
||||
|
} |
||||
|
|
||||
|
MathUtil::Rectangle<u32> GetScaledRect() const { |
||||
|
return {0, GetScaledHeight(), GetScaledWidth(), 0}; |
||||
|
} |
||||
|
|
||||
|
u64 PixelsInBytes(u64 size) const { |
||||
|
return size * CHAR_BIT / GetFormatBpp(pixel_format); |
||||
|
} |
||||
|
|
||||
|
u64 BytesInPixels(u64 pixels) const { |
||||
|
return pixels * GetFormatBpp(pixel_format) / CHAR_BIT; |
||||
|
} |
||||
|
|
||||
|
bool ExactMatch(const SurfaceParams& other_surface) const; |
||||
|
bool CanSubRect(const SurfaceParams& sub_surface) const; |
||||
|
bool CanExpand(const SurfaceParams& expanded_surface) const; |
||||
|
bool CanTexCopy(const SurfaceParams& texcopy_params) const; |
||||
|
|
||||
|
MathUtil::Rectangle<u32> GetSubRect(const SurfaceParams& sub_surface) const; |
||||
|
MathUtil::Rectangle<u32> GetScaledSubRect(const SurfaceParams& sub_surface) const; |
||||
|
|
||||
|
PAddr addr = 0; |
||||
|
PAddr end = 0; |
||||
|
u64 size = 0; |
||||
|
|
||||
|
u32 width = 0; |
||||
|
u32 height = 0; |
||||
|
u32 stride = 0; |
||||
|
u16 res_scale = 1; |
||||
|
|
||||
|
bool is_tiled = false; |
||||
|
PixelFormat pixel_format = PixelFormat::Invalid; |
||||
|
SurfaceType type = SurfaceType::Invalid; |
||||
|
}; |
||||
|
|
||||
|
struct CachedSurface : SurfaceParams { |
||||
|
bool CanFill(const SurfaceParams& dest_surface, SurfaceInterval fill_interval) const; |
||||
|
bool CanCopy(const SurfaceParams& dest_surface, SurfaceInterval copy_interval) const; |
||||
|
|
||||
|
bool IsRegionValid(SurfaceInterval interval) const { |
||||
|
return (invalid_regions.find(interval) == invalid_regions.end()); |
||||
|
} |
||||
|
|
||||
|
bool IsSurfaceFullyInvalid() const { |
||||
|
return (invalid_regions & GetInterval()) == SurfaceRegions(GetInterval()); |
||||
|
} |
||||
|
|
||||
|
bool registered = false; |
||||
|
SurfaceRegions invalid_regions; |
||||
|
|
||||
|
u64 fill_size = 0; /// Number of bytes to read from fill_data |
||||
|
std::array<u8, 4> fill_data; |
||||
|
|
||||
|
OGLTexture texture; |
||||
|
|
||||
|
static constexpr unsigned int GetGLBytesPerPixel(PixelFormat format) { |
||||
|
// OpenGL needs 4 bpp alignment for D24 since using GL_UNSIGNED_INT as type |
||||
|
return format == PixelFormat::Invalid |
||||
|
? 0 |
||||
|
: (format == PixelFormat::D24 || GetFormatType(format) == SurfaceType::Texture) |
||||
|
? 4 |
||||
|
: SurfaceParams::GetFormatBpp(format) / 8; |
||||
|
} |
||||
|
|
||||
|
std::unique_ptr<u8[]> gl_buffer; |
||||
|
size_t gl_buffer_size = 0; |
||||
|
|
||||
|
// Read/Write data in 3DS memory to/from gl_buffer |
||||
|
void LoadGLBuffer(PAddr load_start, PAddr load_end); |
||||
|
void FlushGLBuffer(PAddr flush_start, PAddr flush_end); |
||||
|
|
||||
|
// Upload/Download data in gl_buffer in/to this surface's texture |
||||
|
void UploadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint read_fb_handle, |
||||
|
GLuint draw_fb_handle); |
||||
|
void DownloadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint read_fb_handle, |
||||
|
GLuint draw_fb_handle); |
||||
|
}; |
||||
|
|
||||
|
class RasterizerCacheOpenGL : NonCopyable { |
||||
|
public: |
||||
|
RasterizerCacheOpenGL(); |
||||
|
~RasterizerCacheOpenGL(); |
||||
|
|
||||
|
/// Blit one surface's texture to another |
||||
|
bool BlitSurfaces(const Surface& src_surface, const MathUtil::Rectangle<u32>& src_rect, |
||||
|
const Surface& dst_surface, const MathUtil::Rectangle<u32>& dst_rect); |
||||
|
|
||||
|
void ConvertD24S8toABGR(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rect, |
||||
|
GLuint dst_tex, const MathUtil::Rectangle<u32>& dst_rect); |
||||
|
|
||||
|
/// Copy one surface's region to another |
||||
|
void CopySurface(const Surface& src_surface, const Surface& dst_surface, |
||||
|
SurfaceInterval copy_interval); |
||||
|
|
||||
|
/// Load a texture from 3DS memory to OpenGL and cache it (if not already cached) |
||||
|
Surface GetSurface(const SurfaceParams& params, ScaleMatch match_res_scale, |
||||
|
bool load_if_create); |
||||
|
|
||||
|
/// Attempt to find a subrect (resolution scaled) of a surface, otherwise loads a texture from |
||||
|
/// 3DS memory to OpenGL and caches it (if not already cached) |
||||
|
SurfaceRect_Tuple GetSurfaceSubRect(const SurfaceParams& params, ScaleMatch match_res_scale, |
||||
|
bool load_if_create); |
||||
|
|
||||
|
/// Get a surface based on the texture configuration |
||||
|
Surface GetTextureSurface(const void* config); |
||||
|
|
||||
|
/// Get the color and depth surfaces based on the framebuffer configuration |
||||
|
SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb, |
||||
|
const MathUtil::Rectangle<s32>& viewport_rect); |
||||
|
|
||||
|
/// Get a surface that matches the fill config |
||||
|
Surface GetFillSurface(const void* config); |
||||
|
|
||||
|
/// Get a surface that matches a "texture copy" display transfer config |
||||
|
SurfaceRect_Tuple GetTexCopySurface(const SurfaceParams& params); |
||||
|
|
||||
|
/// Write any cached resources overlapping the region back to memory (if dirty) |
||||
|
void FlushRegion(PAddr addr, u64 size, Surface flush_surface = nullptr); |
||||
|
|
||||
|
/// Mark region as being invalidated by region_owner (nullptr if 3DS memory) |
||||
|
void InvalidateRegion(PAddr addr, u64 size, const Surface& region_owner); |
||||
|
|
||||
|
/// Flush all cached resources tracked by this cache manager |
||||
|
void FlushAll(); |
||||
|
|
||||
|
private: |
||||
|
void DuplicateSurface(const Surface& src_surface, const Surface& dest_surface); |
||||
|
|
||||
|
/// Update surface's texture for given region when necessary |
||||
|
void ValidateSurface(const Surface& surface, PAddr addr, u64 size); |
||||
|
|
||||
|
/// Create a new surface |
||||
|
Surface CreateSurface(const SurfaceParams& params); |
||||
|
|
||||
|
/// Register surface into the cache |
||||
|
void RegisterSurface(const Surface& surface); |
||||
|
|
||||
|
/// Remove surface from the cache |
||||
|
void UnregisterSurface(const Surface& surface); |
||||
|
|
||||
|
/// Increase/decrease the number of surface in pages touching the specified region |
||||
|
void UpdatePagesCachedCount(PAddr addr, u64 size, int delta); |
||||
|
|
||||
|
SurfaceCache surface_cache; |
||||
|
PageMap cached_pages; |
||||
|
SurfaceMap dirty_regions; |
||||
|
SurfaceSet remove_surfaces; |
||||
|
|
||||
|
OGLFramebuffer read_framebuffer; |
||||
|
OGLFramebuffer draw_framebuffer; |
||||
|
|
||||
|
OGLVertexArray attributeless_vao; |
||||
|
OGLBuffer d24s8_abgr_buffer; |
||||
|
GLsizeiptr d24s8_abgr_buffer_size; |
||||
|
OGLShader d24s8_abgr_shader; |
||||
|
GLint d24s8_abgr_tbo_size_u_id; |
||||
|
GLint d24s8_abgr_viewport_u_id; |
||||
|
}; |
||||
@ -0,0 +1,58 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include <string>
|
||||
|
#include <queue>
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/renderer_opengl/gl_shader_decompiler.h"
|
||||
|
|
||||
|
namespace Maxwell3D { |
||||
|
namespace Shader { |
||||
|
namespace Decompiler { |
||||
|
|
||||
|
constexpr u32 PROGRAM_END = MAX_PROGRAM_CODE_LENGTH; |
||||
|
|
||||
|
class Impl { |
||||
|
public: |
||||
|
Impl(const std::array<u32, MAX_PROGRAM_CODE_LENGTH>& program_code, |
||||
|
const std::array<u32, MAX_SWIZZLE_DATA_LENGTH>& swizzle_data, u32 main_offset, |
||||
|
const std::function<std::string(u32)>& inputreg_getter, |
||||
|
const std::function<std::string(u32)>& outputreg_getter, bool sanitize_mul, |
||||
|
const std::string& emit_cb, const std::string& setemit_cb) |
||||
|
: program_code(program_code), swizzle_data(swizzle_data), main_offset(main_offset), |
||||
|
inputreg_getter(inputreg_getter), outputreg_getter(outputreg_getter), |
||||
|
sanitize_mul(sanitize_mul), emit_cb(emit_cb), setemit_cb(setemit_cb) {} |
||||
|
|
||||
|
std::string Decompile() { |
||||
|
UNIMPLEMENTED(); |
||||
|
return {}; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
const std::array<u32, MAX_PROGRAM_CODE_LENGTH>& program_code; |
||||
|
const std::array<u32, MAX_SWIZZLE_DATA_LENGTH>& swizzle_data; |
||||
|
u32 main_offset; |
||||
|
const std::function<std::string(u32)>& inputreg_getter; |
||||
|
const std::function<std::string(u32)>& outputreg_getter; |
||||
|
bool sanitize_mul; |
||||
|
const std::string& emit_cb; |
||||
|
const std::string& setemit_cb; |
||||
|
}; |
||||
|
|
||||
|
std::string DecompileProgram(const std::array<u32, MAX_PROGRAM_CODE_LENGTH>& program_code, |
||||
|
const std::array<u32, MAX_SWIZZLE_DATA_LENGTH>& swizzle_data, |
||||
|
u32 main_offset, |
||||
|
const std::function<std::string(u32)>& inputreg_getter, |
||||
|
const std::function<std::string(u32)>& outputreg_getter, |
||||
|
bool sanitize_mul, const std::string& emit_cb, |
||||
|
const std::string& setemit_cb) { |
||||
|
Impl impl(program_code, swizzle_data, main_offset, inputreg_getter, outputreg_getter, |
||||
|
sanitize_mul, emit_cb, setemit_cb); |
||||
|
return impl.Decompile(); |
||||
|
} |
||||
|
|
||||
|
} // namespace Decompiler
|
||||
|
} // namespace Shader
|
||||
|
} // namespace Maxwell3D
|
||||
@ -0,0 +1,27 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project |
||||
|
// Licensed under GPLv2 or any later version |
||||
|
// Refer to the license.txt file included. |
||||
|
|
||||
|
#include <array> |
||||
|
#include <functional> |
||||
|
#include <string> |
||||
|
#include "common/common_types.h" |
||||
|
|
||||
|
namespace Maxwell3D { |
||||
|
namespace Shader { |
||||
|
namespace Decompiler { |
||||
|
|
||||
|
constexpr size_t MAX_PROGRAM_CODE_LENGTH{0x100000}; |
||||
|
constexpr size_t MAX_SWIZZLE_DATA_LENGTH{0x100000}; |
||||
|
|
||||
|
std::string DecompileProgram(const std::array<u32, MAX_PROGRAM_CODE_LENGTH>& program_code, |
||||
|
const std::array<u32, MAX_SWIZZLE_DATA_LENGTH>& swizzle_data, |
||||
|
u32 main_offset, |
||||
|
const std::function<std::string(u32)>& inputreg_getter, |
||||
|
const std::function<std::string(u32)>& outputreg_getter, |
||||
|
bool sanitize_mul, const std::string& emit_cb = "", |
||||
|
const std::string& setemit_cb = ""); |
||||
|
|
||||
|
} // namespace Decompiler |
||||
|
} // namespace Shader |
||||
|
} // namespace Maxwell3D |
||||
@ -0,0 +1,20 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "video_core/renderer_opengl/gl_shader_gen.h"
|
||||
|
|
||||
|
namespace GLShader { |
||||
|
|
||||
|
std::string GenerateVertexShader(const MaxwellVSConfig& config) { |
||||
|
UNIMPLEMENTED(); |
||||
|
return {}; |
||||
|
} |
||||
|
|
||||
|
std::string GenerateFragmentShader(const MaxwellFSConfig& config) { |
||||
|
UNIMPLEMENTED(); |
||||
|
return {}; |
||||
|
} |
||||
|
|
||||
|
} // namespace GLShader
|
||||
@ -0,0 +1,66 @@ |
|||||
|
// Copyright 2018 yuzu Emulator Project |
||||
|
// Licensed under GPLv2 or any later version |
||||
|
// Refer to the license.txt file included. |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <cstring> |
||||
|
#include <string> |
||||
|
#include <type_traits> |
||||
|
#include "common/hash.h" |
||||
|
|
||||
|
namespace GLShader { |
||||
|
|
||||
|
enum Attributes { |
||||
|
ATTRIBUTE_POSITION, |
||||
|
ATTRIBUTE_COLOR, |
||||
|
ATTRIBUTE_TEXCOORD0, |
||||
|
ATTRIBUTE_TEXCOORD1, |
||||
|
ATTRIBUTE_TEXCOORD2, |
||||
|
ATTRIBUTE_TEXCOORD0_W, |
||||
|
ATTRIBUTE_NORMQUAT, |
||||
|
ATTRIBUTE_VIEW, |
||||
|
}; |
||||
|
|
||||
|
struct MaxwellShaderConfigCommon { |
||||
|
explicit MaxwellShaderConfigCommon(){}; |
||||
|
}; |
||||
|
|
||||
|
struct MaxwellVSConfig : MaxwellShaderConfigCommon { |
||||
|
explicit MaxwellVSConfig() : MaxwellShaderConfigCommon() {} |
||||
|
|
||||
|
bool operator==(const MaxwellVSConfig& o) const { |
||||
|
return std::memcmp(this, &o, sizeof(MaxwellVSConfig)) == 0; |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
struct MaxwellFSConfig : MaxwellShaderConfigCommon { |
||||
|
explicit MaxwellFSConfig() : MaxwellShaderConfigCommon() {} |
||||
|
|
||||
|
bool operator==(const MaxwellFSConfig& o) const { |
||||
|
return std::memcmp(this, &o, sizeof(MaxwellFSConfig)) == 0; |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
std::string GenerateVertexShader(const MaxwellVSConfig& config); |
||||
|
std::string GenerateFragmentShader(const MaxwellFSConfig& config); |
||||
|
|
||||
|
} // namespace GLShader |
||||
|
|
||||
|
namespace std { |
||||
|
|
||||
|
template <> |
||||
|
struct hash<GLShader::MaxwellVSConfig> { |
||||
|
size_t operator()(const GLShader::MaxwellVSConfig& k) const { |
||||
|
return Common::ComputeHash64(&k, sizeof(GLShader::MaxwellVSConfig)); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
template <> |
||||
|
struct hash<GLShader::MaxwellFSConfig> { |
||||
|
size_t operator()(const GLShader::MaxwellFSConfig& k) const { |
||||
|
return Common::ComputeHash64(&k, sizeof(GLShader::MaxwellFSConfig)); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
} // namespace std |
||||
@ -0,0 +1,182 @@ |
|||||
|
// Copyright 2018 Citra Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include <deque>
|
||||
|
#include <vector>
|
||||
|
#include "common/alignment.h"
|
||||
|
#include "common/assert.h"
|
||||
|
#include "video_core/renderer_opengl/gl_state.h"
|
||||
|
#include "video_core/renderer_opengl/gl_stream_buffer.h"
|
||||
|
|
||||
|
class OrphanBuffer : public OGLStreamBuffer { |
||||
|
public: |
||||
|
explicit OrphanBuffer(GLenum target) : OGLStreamBuffer(target) {} |
||||
|
~OrphanBuffer() override; |
||||
|
|
||||
|
private: |
||||
|
void Create(size_t size, size_t sync_subdivide) override; |
||||
|
void Release() override; |
||||
|
|
||||
|
std::pair<u8*, GLintptr> Map(size_t size, size_t alignment) override; |
||||
|
void Unmap() override; |
||||
|
|
||||
|
std::vector<u8> data; |
||||
|
}; |
||||
|
|
||||
|
class StorageBuffer : public OGLStreamBuffer { |
||||
|
public: |
||||
|
explicit StorageBuffer(GLenum target) : OGLStreamBuffer(target) {} |
||||
|
~StorageBuffer() override; |
||||
|
|
||||
|
private: |
||||
|
void Create(size_t size, size_t sync_subdivide) override; |
||||
|
void Release() override; |
||||
|
|
||||
|
std::pair<u8*, GLintptr> Map(size_t size, size_t alignment) override; |
||||
|
void Unmap() override; |
||||
|
|
||||
|
struct Fence { |
||||
|
OGLSync sync; |
||||
|
size_t offset; |
||||
|
}; |
||||
|
std::deque<Fence> head; |
||||
|
std::deque<Fence> tail; |
||||
|
|
||||
|
u8* mapped_ptr; |
||||
|
}; |
||||
|
|
||||
|
OGLStreamBuffer::OGLStreamBuffer(GLenum target) { |
||||
|
gl_target = target; |
||||
|
} |
||||
|
|
||||
|
GLuint OGLStreamBuffer::GetHandle() const { |
||||
|
return gl_buffer.handle; |
||||
|
} |
||||
|
|
||||
|
std::unique_ptr<OGLStreamBuffer> OGLStreamBuffer::MakeBuffer(bool storage_buffer, GLenum target) { |
||||
|
if (storage_buffer) { |
||||
|
return std::make_unique<StorageBuffer>(target); |
||||
|
} |
||||
|
return std::make_unique<OrphanBuffer>(target); |
||||
|
} |
||||
|
|
||||
|
OrphanBuffer::~OrphanBuffer() { |
||||
|
Release(); |
||||
|
} |
||||
|
|
||||
|
void OrphanBuffer::Create(size_t size, size_t /*sync_subdivide*/) { |
||||
|
buffer_pos = 0; |
||||
|
buffer_size = size; |
||||
|
data.resize(buffer_size); |
||||
|
|
||||
|
if (gl_buffer.handle == 0) { |
||||
|
gl_buffer.Create(); |
||||
|
glBindBuffer(gl_target, gl_buffer.handle); |
||||
|
} |
||||
|
|
||||
|
glBufferData(gl_target, static_cast<GLsizeiptr>(buffer_size), nullptr, GL_STREAM_DRAW); |
||||
|
} |
||||
|
|
||||
|
void OrphanBuffer::Release() { |
||||
|
gl_buffer.Release(); |
||||
|
} |
||||
|
|
||||
|
std::pair<u8*, GLintptr> OrphanBuffer::Map(size_t size, size_t alignment) { |
||||
|
buffer_pos = Common::AlignUp(buffer_pos, alignment); |
||||
|
|
||||
|
if (buffer_pos + size > buffer_size) { |
||||
|
Create(std::max(buffer_size, size), 0); |
||||
|
} |
||||
|
|
||||
|
mapped_size = size; |
||||
|
return std::make_pair(&data[buffer_pos], static_cast<GLintptr>(buffer_pos)); |
||||
|
} |
||||
|
|
||||
|
void OrphanBuffer::Unmap() { |
||||
|
glBufferSubData(gl_target, static_cast<GLintptr>(buffer_pos), |
||||
|
static_cast<GLsizeiptr>(mapped_size), &data[buffer_pos]); |
||||
|
buffer_pos += mapped_size; |
||||
|
} |
||||
|
|
||||
|
StorageBuffer::~StorageBuffer() { |
||||
|
Release(); |
||||
|
} |
||||
|
|
||||
|
void StorageBuffer::Create(size_t size, size_t sync_subdivide) { |
||||
|
if (gl_buffer.handle != 0) |
||||
|
return; |
||||
|
|
||||
|
buffer_pos = 0; |
||||
|
buffer_size = size; |
||||
|
buffer_sync_subdivide = std::max<size_t>(sync_subdivide, 1); |
||||
|
|
||||
|
gl_buffer.Create(); |
||||
|
glBindBuffer(gl_target, gl_buffer.handle); |
||||
|
|
||||
|
glBufferStorage(gl_target, static_cast<GLsizeiptr>(buffer_size), nullptr, |
||||
|
GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT); |
||||
|
mapped_ptr = reinterpret_cast<u8*>( |
||||
|
glMapBufferRange(gl_target, 0, static_cast<GLsizeiptr>(buffer_size), |
||||
|
GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_FLUSH_EXPLICIT_BIT)); |
||||
|
} |
||||
|
|
||||
|
void StorageBuffer::Release() { |
||||
|
if (gl_buffer.handle == 0) |
||||
|
return; |
||||
|
|
||||
|
glUnmapBuffer(gl_target); |
||||
|
|
||||
|
gl_buffer.Release(); |
||||
|
head.clear(); |
||||
|
tail.clear(); |
||||
|
} |
||||
|
|
||||
|
std::pair<u8*, GLintptr> StorageBuffer::Map(size_t size, size_t alignment) { |
||||
|
ASSERT(size <= buffer_size); |
||||
|
|
||||
|
OGLSync sync; |
||||
|
|
||||
|
buffer_pos = Common::AlignUp(buffer_pos, alignment); |
||||
|
size_t effective_offset = Common::AlignDown(buffer_pos, buffer_sync_subdivide); |
||||
|
|
||||
|
if (!head.empty() && |
||||
|
(effective_offset > head.back().offset || buffer_pos + size > buffer_size)) { |
||||
|
ASSERT(head.back().sync.handle == 0); |
||||
|
head.back().sync.Create(); |
||||
|
} |
||||
|
|
||||
|
if (buffer_pos + size > buffer_size) { |
||||
|
if (!tail.empty()) { |
||||
|
std::swap(sync, tail.back().sync); |
||||
|
tail.clear(); |
||||
|
} |
||||
|
std::swap(tail, head); |
||||
|
buffer_pos = 0; |
||||
|
effective_offset = 0; |
||||
|
} |
||||
|
|
||||
|
while (!tail.empty() && buffer_pos + size > tail.front().offset) { |
||||
|
std::swap(sync, tail.front().sync); |
||||
|
tail.pop_front(); |
||||
|
} |
||||
|
|
||||
|
if (sync.handle != 0) { |
||||
|
glClientWaitSync(sync.handle, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED); |
||||
|
sync.Release(); |
||||
|
} |
||||
|
|
||||
|
if (head.empty() || effective_offset > head.back().offset) { |
||||
|
head.emplace_back(); |
||||
|
head.back().offset = effective_offset; |
||||
|
} |
||||
|
|
||||
|
mapped_size = size; |
||||
|
return std::make_pair(&mapped_ptr[buffer_pos], static_cast<GLintptr>(buffer_pos)); |
||||
|
} |
||||
|
|
||||
|
void StorageBuffer::Unmap() { |
||||
|
glFlushMappedBufferRange(gl_target, static_cast<GLintptr>(buffer_pos), |
||||
|
static_cast<GLsizeiptr>(mapped_size)); |
||||
|
buffer_pos += mapped_size; |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
// Copyright 2018 Citra Emulator Project |
||||
|
// Licensed under GPLv2 or any later version |
||||
|
// Refer to the license.txt file included. |
||||
|
|
||||
|
#include <memory> |
||||
|
#include <glad/glad.h> |
||||
|
#include "common/common_types.h" |
||||
|
#include "video_core/renderer_opengl/gl_resource_manager.h" |
||||
|
|
||||
|
class OGLStreamBuffer : private NonCopyable { |
||||
|
public: |
||||
|
explicit OGLStreamBuffer(GLenum target); |
||||
|
virtual ~OGLStreamBuffer() = default; |
||||
|
|
||||
|
public: |
||||
|
static std::unique_ptr<OGLStreamBuffer> MakeBuffer(bool storage_buffer, GLenum target); |
||||
|
|
||||
|
virtual void Create(size_t size, size_t sync_subdivide) = 0; |
||||
|
virtual void Release() {} |
||||
|
|
||||
|
GLuint GetHandle() const; |
||||
|
|
||||
|
virtual std::pair<u8*, GLintptr> Map(size_t size, size_t alignment) = 0; |
||||
|
virtual void Unmap() = 0; |
||||
|
|
||||
|
protected: |
||||
|
OGLBuffer gl_buffer; |
||||
|
GLenum gl_target; |
||||
|
|
||||
|
size_t buffer_pos = 0; |
||||
|
size_t buffer_size = 0; |
||||
|
size_t buffer_sync_subdivide = 0; |
||||
|
size_t mapped_size = 0; |
||||
|
}; |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue