Merge pull request #2514 from ReinUsesLisp/opengl-compat
video_core: Drop OpenGL core in favor of OpenGL compatibility
This commit is contained in:
commit
de33ad25f5
24 changed files with 45 additions and 252 deletions
|
@ -71,16 +71,6 @@ GLintptr OGLBufferCache::UploadHostMemory(const void* raw_pointer, std::size_t s
|
|||
return uploaded_offset;
|
||||
}
|
||||
|
||||
std::tuple<u8*, GLintptr> OGLBufferCache::ReserveMemory(std::size_t size, std::size_t alignment) {
|
||||
AlignBuffer(alignment);
|
||||
u8* const uploaded_ptr = buffer_ptr;
|
||||
const GLintptr uploaded_offset = buffer_offset;
|
||||
|
||||
buffer_ptr += size;
|
||||
buffer_offset += size;
|
||||
return std::make_tuple(uploaded_ptr, uploaded_offset);
|
||||
}
|
||||
|
||||
bool OGLBufferCache::Map(std::size_t max_size) {
|
||||
bool invalidate;
|
||||
std::tie(buffer_ptr, buffer_offset_base, invalidate) =
|
||||
|
|
|
@ -61,9 +61,6 @@ public:
|
|||
/// Uploads from a host memory. Returns host's buffer offset where it's been allocated.
|
||||
GLintptr UploadHostMemory(const void* raw_pointer, std::size_t size, std::size_t alignment = 4);
|
||||
|
||||
/// Reserves memory to be used by host's CPU. Returns mapped address and offset.
|
||||
std::tuple<u8*, GLintptr> ReserveMemory(std::size_t size, std::size_t alignment = 4);
|
||||
|
||||
bool Map(std::size_t max_size);
|
||||
void Unmap();
|
||||
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
// Copyright 2018 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/core.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
#include "video_core/renderer_opengl/gl_buffer_cache.h"
|
||||
#include "video_core/renderer_opengl/gl_primitive_assembler.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
constexpr u32 TRIANGLES_PER_QUAD = 6;
|
||||
constexpr std::array<u32, TRIANGLES_PER_QUAD> QUAD_MAP = {0, 1, 2, 0, 2, 3};
|
||||
|
||||
PrimitiveAssembler::PrimitiveAssembler(OGLBufferCache& buffer_cache) : buffer_cache(buffer_cache) {}
|
||||
|
||||
PrimitiveAssembler::~PrimitiveAssembler() = default;
|
||||
|
||||
std::size_t PrimitiveAssembler::CalculateQuadSize(u32 count) const {
|
||||
ASSERT_MSG(count % 4 == 0, "Quad count is expected to be a multiple of 4");
|
||||
return (count / 4) * TRIANGLES_PER_QUAD * sizeof(GLuint);
|
||||
}
|
||||
|
||||
GLintptr PrimitiveAssembler::MakeQuadArray(u32 first, u32 count) {
|
||||
const std::size_t size{CalculateQuadSize(count)};
|
||||
auto [dst_pointer, index_offset] = buffer_cache.ReserveMemory(size);
|
||||
|
||||
for (u32 primitive = 0; primitive < count / 4; ++primitive) {
|
||||
for (u32 i = 0; i < TRIANGLES_PER_QUAD; ++i) {
|
||||
const u32 index = first + primitive * 4 + QUAD_MAP[i];
|
||||
std::memcpy(dst_pointer, &index, sizeof(index));
|
||||
dst_pointer += sizeof(index);
|
||||
}
|
||||
}
|
||||
|
||||
return index_offset;
|
||||
}
|
||||
|
||||
GLintptr PrimitiveAssembler::MakeQuadIndexed(GPUVAddr gpu_addr, std::size_t index_size, u32 count) {
|
||||
const std::size_t map_size{CalculateQuadSize(count)};
|
||||
auto [dst_pointer, index_offset] = buffer_cache.ReserveMemory(map_size);
|
||||
|
||||
auto& memory_manager = Core::System::GetInstance().GPU().MemoryManager();
|
||||
const u8* source{memory_manager.GetPointer(gpu_addr)};
|
||||
|
||||
for (u32 primitive = 0; primitive < count / 4; ++primitive) {
|
||||
for (std::size_t i = 0; i < TRIANGLES_PER_QUAD; ++i) {
|
||||
const u32 index = primitive * 4 + QUAD_MAP[i];
|
||||
const u8* src_offset = source + (index * index_size);
|
||||
|
||||
std::memcpy(dst_pointer, src_offset, index_size);
|
||||
dst_pointer += index_size;
|
||||
}
|
||||
}
|
||||
|
||||
return index_offset;
|
||||
}
|
||||
|
||||
} // namespace OpenGL
|
|
@ -1,31 +0,0 @@
|
|||
// Copyright 2018 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
class OGLBufferCache;
|
||||
|
||||
class PrimitiveAssembler {
|
||||
public:
|
||||
explicit PrimitiveAssembler(OGLBufferCache& buffer_cache);
|
||||
~PrimitiveAssembler();
|
||||
|
||||
/// Calculates the size required by MakeQuadArray and MakeQuadIndexed.
|
||||
std::size_t CalculateQuadSize(u32 count) const;
|
||||
|
||||
GLintptr MakeQuadArray(u32 first, u32 count);
|
||||
|
||||
GLintptr MakeQuadIndexed(GPUVAddr gpu_addr, std::size_t index_size, u32 count);
|
||||
|
||||
private:
|
||||
OGLBufferCache& buffer_cache;
|
||||
};
|
||||
|
||||
} // namespace OpenGL
|
|
@ -246,29 +246,6 @@ DrawParameters RasterizerOpenGL::SetupDraw() {
|
|||
DrawParameters params{};
|
||||
params.current_instance = gpu.state.current_instance;
|
||||
|
||||
if (regs.draw.topology == Maxwell::PrimitiveTopology::Quads) {
|
||||
MICROPROFILE_SCOPE(OpenGL_PrimitiveAssembly);
|
||||
|
||||
params.use_indexed = true;
|
||||
params.primitive_mode = GL_TRIANGLES;
|
||||
|
||||
if (is_indexed) {
|
||||
params.index_format = MaxwellToGL::IndexFormat(regs.index_array.format);
|
||||
params.count = (regs.index_array.count / 4) * 6;
|
||||
params.index_buffer_offset = primitive_assembler.MakeQuadIndexed(
|
||||
regs.index_array.IndexStart(), regs.index_array.FormatSizeInBytes(),
|
||||
regs.index_array.count);
|
||||
params.base_vertex = static_cast<GLint>(regs.vb_element_base);
|
||||
} else {
|
||||
// MakeQuadArray always generates u32 indexes
|
||||
params.index_format = GL_UNSIGNED_INT;
|
||||
params.count = (regs.vertex_buffer.count / 4) * 6;
|
||||
params.index_buffer_offset = primitive_assembler.MakeQuadArray(
|
||||
regs.vertex_buffer.first, regs.vertex_buffer.count);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
params.use_indexed = is_indexed;
|
||||
params.primitive_mode = MaxwellToGL::PrimitiveTopology(regs.draw.topology);
|
||||
|
||||
|
@ -686,30 +663,19 @@ void RasterizerOpenGL::DrawArrays() {
|
|||
SyncCullMode();
|
||||
SyncPrimitiveRestart();
|
||||
SyncScissorTest(state);
|
||||
// Alpha Testing is synced on shaders.
|
||||
SyncTransformFeedback();
|
||||
SyncPointState();
|
||||
CheckAlphaTests();
|
||||
SyncPolygonOffset();
|
||||
// TODO(bunnei): Sync framebuffer_scale uniform here
|
||||
// TODO(bunnei): Sync scissorbox uniform(s) here
|
||||
SyncAlphaTest();
|
||||
|
||||
// Draw the vertex batch
|
||||
const bool is_indexed = accelerate_draw == AccelDraw::Indexed;
|
||||
|
||||
std::size_t buffer_size = CalculateVertexArraysSize();
|
||||
|
||||
// Add space for index buffer (keeping in mind non-core primitives)
|
||||
switch (regs.draw.topology) {
|
||||
case Maxwell::PrimitiveTopology::Quads:
|
||||
buffer_size = Common::AlignUp(buffer_size, 4) +
|
||||
primitive_assembler.CalculateQuadSize(regs.vertex_buffer.count);
|
||||
break;
|
||||
default:
|
||||
if (is_indexed) {
|
||||
buffer_size = Common::AlignUp(buffer_size, 4) + CalculateIndexBufferSize();
|
||||
}
|
||||
break;
|
||||
// Add space for index buffer
|
||||
if (is_indexed) {
|
||||
buffer_size = Common::AlignUp(buffer_size, 4) + CalculateIndexBufferSize();
|
||||
}
|
||||
|
||||
// Uniform space for the 5 shader stages
|
||||
|
@ -1152,10 +1118,17 @@ void RasterizerOpenGL::SyncPolygonOffset() {
|
|||
state.polygon_offset.clamp = regs.polygon_offset_clamp;
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::CheckAlphaTests() {
|
||||
void RasterizerOpenGL::SyncAlphaTest() {
|
||||
const auto& regs = system.GPU().Maxwell3D().regs;
|
||||
UNIMPLEMENTED_IF_MSG(regs.alpha_test_enabled != 0 && regs.rt_control.count > 1,
|
||||
"Alpha Testing is enabled with more than one rendertarget");
|
||||
|
||||
state.alpha_test.enabled = regs.alpha_test_enabled;
|
||||
if (!state.alpha_test.enabled) {
|
||||
return;
|
||||
}
|
||||
state.alpha_test.func = MaxwellToGL::ComparisonOp(regs.alpha_test_func);
|
||||
state.alpha_test.ref = regs.alpha_test_ref;
|
||||
}
|
||||
|
||||
} // namespace OpenGL
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include "video_core/renderer_opengl/gl_buffer_cache.h"
|
||||
#include "video_core/renderer_opengl/gl_device.h"
|
||||
#include "video_core/renderer_opengl/gl_global_cache.h"
|
||||
#include "video_core/renderer_opengl/gl_primitive_assembler.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_sampler_cache.h"
|
||||
|
@ -167,8 +166,8 @@ private:
|
|||
/// Syncs the polygon offsets
|
||||
void SyncPolygonOffset();
|
||||
|
||||
/// Check asserts for alpha testing.
|
||||
void CheckAlphaTests();
|
||||
/// Syncs the alpha test state to match the guest state
|
||||
void SyncAlphaTest();
|
||||
|
||||
/// Check for extension that are not strictly required
|
||||
/// but are needed for correct emulation
|
||||
|
@ -197,7 +196,6 @@ private:
|
|||
|
||||
static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024;
|
||||
OGLBufferCache buffer_cache;
|
||||
PrimitiveAssembler primitive_assembler{buffer_cache};
|
||||
|
||||
BindBuffersRangePushBuffer bind_ubo_pushbuffer{GL_UNIFORM_BUFFER};
|
||||
BindBuffersRangePushBuffer bind_ssbo_pushbuffer{GL_SHADER_STORAGE_BUFFER};
|
||||
|
|
|
@ -1467,27 +1467,9 @@ private:
|
|||
|
||||
UNIMPLEMENTED_IF_MSG(header.ps.omap.sample_mask != 0, "Sample mask write is unimplemented");
|
||||
|
||||
code.AddLine("if (alpha_test[0] != 0) {{");
|
||||
++code.scope;
|
||||
// We start on the register containing the alpha value in the first RT.
|
||||
u32 current_reg = 3;
|
||||
for (u32 render_target = 0; render_target < Maxwell::NumRenderTargets; ++render_target) {
|
||||
// TODO(Blinkhawk): verify the behavior of alpha testing on hardware when
|
||||
// multiple render targets are used.
|
||||
if (header.ps.IsColorComponentOutputEnabled(render_target, 0) ||
|
||||
header.ps.IsColorComponentOutputEnabled(render_target, 1) ||
|
||||
header.ps.IsColorComponentOutputEnabled(render_target, 2) ||
|
||||
header.ps.IsColorComponentOutputEnabled(render_target, 3)) {
|
||||
code.AddLine("if (!AlphaFunc({})) discard;", SafeGetRegister(current_reg));
|
||||
current_reg += 4;
|
||||
}
|
||||
}
|
||||
--code.scope;
|
||||
code.AddLine("}}");
|
||||
|
||||
// Write the color outputs using the data in the shader registers, disabled
|
||||
// rendertargets/components are skipped in the register assignment.
|
||||
current_reg = 0;
|
||||
u32 current_reg = 0;
|
||||
for (u32 render_target = 0; render_target < Maxwell::NumRenderTargets; ++render_target) {
|
||||
// TODO(Subv): Figure out how dual-source blending is configured in the Switch.
|
||||
for (u32 component = 0; component < 4; ++component) {
|
||||
|
|
|
@ -26,7 +26,6 @@ ProgramResult GenerateVertexShader(const Device& device, const ShaderSetup& setu
|
|||
layout (std140, binding = EMULATION_UBO_BINDING) uniform vs_config {
|
||||
vec4 viewport_flip;
|
||||
uvec4 config_pack; // instance_id, flip_stage, y_direction, padding
|
||||
uvec4 alpha_test;
|
||||
};
|
||||
|
||||
)";
|
||||
|
@ -78,7 +77,6 @@ ProgramResult GenerateGeometryShader(const Device& device, const ShaderSetup& se
|
|||
layout (std140, binding = EMULATION_UBO_BINDING) uniform gs_config {
|
||||
vec4 viewport_flip;
|
||||
uvec4 config_pack; // instance_id, flip_stage, y_direction, padding
|
||||
uvec4 alpha_test;
|
||||
};
|
||||
|
||||
)";
|
||||
|
@ -114,33 +112,8 @@ layout (location = 7) out vec4 FragColor7;
|
|||
layout (std140, binding = EMULATION_UBO_BINDING) uniform fs_config {
|
||||
vec4 viewport_flip;
|
||||
uvec4 config_pack; // instance_id, flip_stage, y_direction, padding
|
||||
uvec4 alpha_test;
|
||||
};
|
||||
|
||||
bool AlphaFunc(in float value) {
|
||||
float ref = uintBitsToFloat(alpha_test[2]);
|
||||
switch (alpha_test[1]) {
|
||||
case 1:
|
||||
return false;
|
||||
case 2:
|
||||
return value < ref;
|
||||
case 3:
|
||||
return value == ref;
|
||||
case 4:
|
||||
return value <= ref;
|
||||
case 5:
|
||||
return value > ref;
|
||||
case 6:
|
||||
return value != ref;
|
||||
case 7:
|
||||
return value >= ref;
|
||||
case 8:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
)";
|
||||
const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET);
|
||||
ProgramResult program =
|
||||
|
|
|
@ -48,17 +48,6 @@ void MaxwellUniformData::SetFromRegs(const Maxwell3D& maxwell, std::size_t shade
|
|||
viewport_flip[0] = regs.viewport_transform[0].scale_x < 0.0 ? -1.0f : 1.0f;
|
||||
viewport_flip[1] = regs.viewport_transform[0].scale_y < 0.0 ? -1.0f : 1.0f;
|
||||
|
||||
auto func{static_cast<u32>(regs.alpha_test_func)};
|
||||
// Normalize the gl variants of opCompare to be the same as the normal variants
|
||||
const u32 op_gl_variant_base = static_cast<u32>(Maxwell3D::Regs::ComparisonOp::Never);
|
||||
if (func >= op_gl_variant_base) {
|
||||
func = func - op_gl_variant_base + 1U;
|
||||
}
|
||||
|
||||
alpha_test.enabled = regs.alpha_test_enabled;
|
||||
alpha_test.func = func;
|
||||
alpha_test.ref = regs.alpha_test_ref;
|
||||
|
||||
instance_id = state.current_instance;
|
||||
|
||||
// Assign in which stage the position has to be flipped
|
||||
|
|
|
@ -27,14 +27,8 @@ struct MaxwellUniformData {
|
|||
GLuint flip_stage;
|
||||
GLfloat y_direction;
|
||||
};
|
||||
struct alignas(16) {
|
||||
GLuint enabled;
|
||||
GLuint func;
|
||||
GLfloat ref;
|
||||
GLuint padding;
|
||||
} alpha_test;
|
||||
};
|
||||
static_assert(sizeof(MaxwellUniformData) == 48, "MaxwellUniformData structure size is incorrect");
|
||||
static_assert(sizeof(MaxwellUniformData) == 32, "MaxwellUniformData structure size is incorrect");
|
||||
static_assert(sizeof(MaxwellUniformData) < 16384,
|
||||
"MaxwellUniformData structure must be less than 16kb as per the OpenGL spec");
|
||||
|
||||
|
|
|
@ -156,6 +156,10 @@ OpenGLState::OpenGLState() {
|
|||
polygon_offset.factor = 0.0f;
|
||||
polygon_offset.units = 0.0f;
|
||||
polygon_offset.clamp = 0.0f;
|
||||
|
||||
alpha_test.enabled = false;
|
||||
alpha_test.func = GL_ALWAYS;
|
||||
alpha_test.ref = 0.0f;
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyDefaultState() {
|
||||
|
@ -461,6 +465,14 @@ void OpenGLState::ApplyPolygonOffset() const {
|
|||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyAlphaTest() const {
|
||||
Enable(GL_ALPHA_TEST, cur_state.alpha_test.enabled, alpha_test.enabled);
|
||||
if (UpdateTie(std::tie(cur_state.alpha_test.func, cur_state.alpha_test.ref),
|
||||
std::tie(alpha_test.func, alpha_test.ref))) {
|
||||
glAlphaFunc(alpha_test.func, alpha_test.ref);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyTextures() const {
|
||||
bool has_delta{};
|
||||
std::size_t first{};
|
||||
|
@ -533,6 +545,7 @@ void OpenGLState::Apply() const {
|
|||
ApplyTextures();
|
||||
ApplySamplers();
|
||||
ApplyPolygonOffset();
|
||||
ApplyAlphaTest();
|
||||
}
|
||||
|
||||
void OpenGLState::EmulateViewportWithScissor() {
|
||||
|
|
|
@ -172,6 +172,12 @@ public:
|
|||
GLfloat clamp;
|
||||
} polygon_offset;
|
||||
|
||||
struct {
|
||||
bool enabled; // GL_ALPHA_TEST
|
||||
GLenum func; // GL_ALPHA_TEST_FUNC
|
||||
GLfloat ref; // GL_ALPHA_TEST_REF
|
||||
} alpha_test;
|
||||
|
||||
std::array<bool, 8> clip_distance; // GL_CLIP_DISTANCE
|
||||
|
||||
OpenGLState();
|
||||
|
@ -215,6 +221,7 @@ public:
|
|||
void ApplySamplers() const;
|
||||
void ApplyDepthClamp() const;
|
||||
void ApplyPolygonOffset() const;
|
||||
void ApplyAlphaTest() const;
|
||||
|
||||
/// Set the initial OpenGL state
|
||||
static void ApplyDefaultState();
|
||||
|
|
|
@ -128,6 +128,8 @@ inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) {
|
|||
return GL_TRIANGLE_STRIP;
|
||||
case Maxwell::PrimitiveTopology::TriangleFan:
|
||||
return GL_TRIANGLE_FAN;
|
||||
case Maxwell::PrimitiveTopology::Quads:
|
||||
return GL_QUADS;
|
||||
default:
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented topology={}", static_cast<u32>(topology));
|
||||
UNREACHABLE();
|
||||
|
@ -173,11 +175,8 @@ inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) {
|
|||
return GL_CLAMP_TO_EDGE;
|
||||
case Tegra::Texture::WrapMode::Border:
|
||||
return GL_CLAMP_TO_BORDER;
|
||||
case Tegra::Texture::WrapMode::ClampOGL:
|
||||
// TODO(Subv): GL_CLAMP was removed as of OpenGL 3.1, to implement GL_CLAMP, we can use
|
||||
// GL_CLAMP_TO_BORDER to get the border color of the texture, and then sample the edge to
|
||||
// manually mix them. However the shader part of this is not yet implemented.
|
||||
return GL_CLAMP_TO_BORDER;
|
||||
case Tegra::Texture::WrapMode::Clamp:
|
||||
return GL_CLAMP;
|
||||
case Tegra::Texture::WrapMode::MirrorOnceClampToEdge:
|
||||
return GL_MIRROR_CLAMP_TO_EDGE;
|
||||
case Tegra::Texture::WrapMode::MirrorOnceBorder:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue