Browse Source
Merge pull request #3301 from ReinUsesLisp/state-tracker
Merge pull request #3301 from ReinUsesLisp/state-tracker
video_core: Remove gl_state and use a state tracker based on dirty flagsnce_cpp
committed by
GitHub
50 changed files with 1578 additions and 1891 deletions
-
16src/common/math_util.h
-
1src/core/core.cpp
-
8src/video_core/CMakeLists.txt
-
46src/video_core/dirty_flags.cpp
-
51src/video_core/dirty_flags.h
-
2src/video_core/dma_pusher.cpp
-
2src/video_core/engines/kepler_compute.cpp
-
2src/video_core/engines/kepler_memory.cpp
-
187src/video_core/engines/maxwell_3d.cpp
-
150src/video_core/engines/maxwell_3d.h
-
2src/video_core/engines/maxwell_dma.cpp
-
3src/video_core/rasterizer_interface.h
-
4src/video_core/renderer_opengl/gl_framebuffer_cache.cpp
-
2src/video_core/renderer_opengl/gl_framebuffer_cache.h
-
869src/video_core/renderer_opengl/gl_rasterizer.cpp
-
45src/video_core/renderer_opengl/gl_rasterizer.h
-
28src/video_core/renderer_opengl/gl_resource_manager.cpp
-
25src/video_core/renderer_opengl/gl_resource_manager.h
-
3src/video_core/renderer_opengl/gl_shader_cache.cpp
-
5src/video_core/renderer_opengl/gl_shader_decompiler.cpp
-
2src/video_core/renderer_opengl/gl_shader_decompiler.h
-
16src/video_core/renderer_opengl/gl_shader_manager.cpp
-
18src/video_core/renderer_opengl/gl_shader_manager.h
-
569src/video_core/renderer_opengl/gl_state.cpp
-
251src/video_core/renderer_opengl/gl_state.h
-
238src/video_core/renderer_opengl/gl_state_tracker.cpp
-
204src/video_core/renderer_opengl/gl_state_tracker.h
-
1src/video_core/renderer_opengl/gl_stream_buffer.cpp
-
47src/video_core/renderer_opengl/gl_texture_cache.cpp
-
10src/video_core/renderer_opengl/gl_texture_cache.h
-
14src/video_core/renderer_opengl/maxwell_to_gl.h
-
206src/video_core/renderer_opengl/renderer_opengl.cpp
-
14src/video_core/renderer_opengl/renderer_opengl.h
-
13src/video_core/renderer_opengl/utils.cpp
-
9src/video_core/renderer_opengl/utils.h
-
15src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
-
8src/video_core/renderer_vulkan/fixed_pipeline_state.h
-
14src/video_core/renderer_vulkan/maxwell_to_vk.cpp
-
4src/video_core/renderer_vulkan/maxwell_to_vk.h
-
8src/video_core/renderer_vulkan/renderer_vulkan.cpp
-
4src/video_core/renderer_vulkan/renderer_vulkan.h
-
5src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
-
69src/video_core/renderer_vulkan/vk_rasterizer.cpp
-
17src/video_core/renderer_vulkan/vk_rasterizer.h
-
21src/video_core/renderer_vulkan/vk_scheduler.cpp
-
42src/video_core/renderer_vulkan/vk_scheduler.h
-
101src/video_core/renderer_vulkan/vk_state_tracker.cpp
-
79src/video_core/renderer_vulkan/vk_state_tracker.h
-
1src/video_core/renderer_vulkan/vk_texture_cache.cpp
-
18src/video_core/texture_cache/texture_cache.h
@ -0,0 +1,46 @@ |
|||||
|
// Copyright 2019 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include <array>
|
||||
|
#include <cstddef>
|
||||
|
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "video_core/dirty_flags.h"
|
||||
|
|
||||
|
#define OFF(field_name) MAXWELL3D_REG_INDEX(field_name)
|
||||
|
#define NUM(field_name) (sizeof(::Tegra::Engines::Maxwell3D::Regs::field_name) / sizeof(u32))
|
||||
|
|
||||
|
namespace VideoCommon::Dirty { |
||||
|
|
||||
|
using Tegra::Engines::Maxwell3D; |
||||
|
|
||||
|
void SetupCommonOnWriteStores(Tegra::Engines::Maxwell3D::DirtyState::Flags& store) { |
||||
|
store[RenderTargets] = true; |
||||
|
store[ZetaBuffer] = true; |
||||
|
for (std::size_t i = 0; i < Maxwell3D::Regs::NumRenderTargets; ++i) { |
||||
|
store[ColorBuffer0 + i] = true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyRenderTargets(Tegra::Engines::Maxwell3D::DirtyState::Tables& tables) { |
||||
|
static constexpr std::size_t num_per_rt = NUM(rt[0]); |
||||
|
static constexpr std::size_t begin = OFF(rt); |
||||
|
static constexpr std::size_t num = num_per_rt * Maxwell3D::Regs::NumRenderTargets; |
||||
|
for (std::size_t rt = 0; rt < Maxwell3D::Regs::NumRenderTargets; ++rt) { |
||||
|
FillBlock(tables[0], begin + rt * num_per_rt, num_per_rt, ColorBuffer0 + rt); |
||||
|
} |
||||
|
FillBlock(tables[1], begin, num, RenderTargets); |
||||
|
|
||||
|
static constexpr std::array zeta_flags{ZetaBuffer, RenderTargets}; |
||||
|
for (std::size_t i = 0; i < std::size(zeta_flags); ++i) { |
||||
|
const u8 flag = zeta_flags[i]; |
||||
|
auto& table = tables[i]; |
||||
|
table[OFF(zeta_enable)] = flag; |
||||
|
table[OFF(zeta_width)] = flag; |
||||
|
table[OFF(zeta_height)] = flag; |
||||
|
FillBlock(table, OFF(zeta), NUM(zeta), flag); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} // namespace VideoCommon::Dirty
|
||||
@ -0,0 +1,51 @@ |
|||||
|
// Copyright 2019 yuzu Emulator Project |
||||
|
// Licensed under GPLv2 or any later version |
||||
|
// Refer to the license.txt file included. |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <algorithm> |
||||
|
#include <cstddef> |
||||
|
#include <iterator> |
||||
|
|
||||
|
#include "common/common_types.h" |
||||
|
#include "video_core/engines/maxwell_3d.h" |
||||
|
|
||||
|
namespace VideoCommon::Dirty { |
||||
|
|
||||
|
enum : u8 { |
||||
|
NullEntry = 0, |
||||
|
|
||||
|
RenderTargets, |
||||
|
ColorBuffer0, |
||||
|
ColorBuffer1, |
||||
|
ColorBuffer2, |
||||
|
ColorBuffer3, |
||||
|
ColorBuffer4, |
||||
|
ColorBuffer5, |
||||
|
ColorBuffer6, |
||||
|
ColorBuffer7, |
||||
|
ZetaBuffer, |
||||
|
|
||||
|
LastCommonEntry, |
||||
|
}; |
||||
|
|
||||
|
template <typename Integer> |
||||
|
void FillBlock(Tegra::Engines::Maxwell3D::DirtyState::Table& table, std::size_t begin, |
||||
|
std::size_t num, Integer dirty_index) { |
||||
|
const auto it = std::begin(table) + begin; |
||||
|
std::fill(it, it + num, static_cast<u8>(dirty_index)); |
||||
|
} |
||||
|
|
||||
|
template <typename Integer1, typename Integer2> |
||||
|
void FillBlock(Tegra::Engines::Maxwell3D::DirtyState::Tables& tables, std::size_t begin, |
||||
|
std::size_t num, Integer1 index_a, Integer2 index_b) { |
||||
|
FillBlock(tables[0], begin, num, index_a); |
||||
|
FillBlock(tables[1], begin, num, index_b); |
||||
|
} |
||||
|
|
||||
|
void SetupCommonOnWriteStores(Tegra::Engines::Maxwell3D::DirtyState::Flags& store); |
||||
|
|
||||
|
void SetupDirtyRenderTargets(Tegra::Engines::Maxwell3D::DirtyState::Tables& tables); |
||||
|
|
||||
|
} // namespace VideoCommon::Dirty |
||||
869
src/video_core/renderer_opengl/gl_rasterizer.cpp
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,569 +0,0 @@ |
|||||
// Copyright 2015 Citra Emulator Project
|
|
||||
// Licensed under GPLv2 or any later version
|
|
||||
// Refer to the license.txt file included.
|
|
||||
|
|
||||
#include <algorithm>
|
|
||||
#include <iterator>
|
|
||||
#include <glad/glad.h>
|
|
||||
#include "common/assert.h"
|
|
||||
#include "common/logging/log.h"
|
|
||||
#include "common/microprofile.h"
|
|
||||
#include "video_core/renderer_opengl/gl_state.h"
|
|
||||
|
|
||||
MICROPROFILE_DEFINE(OpenGL_State, "OpenGL", "State Change", MP_RGB(192, 128, 128)); |
|
||||
|
|
||||
namespace OpenGL { |
|
||||
|
|
||||
using Maxwell = Tegra::Engines::Maxwell3D::Regs; |
|
||||
|
|
||||
OpenGLState OpenGLState::cur_state; |
|
||||
|
|
||||
namespace { |
|
||||
|
|
||||
template <typename T> |
|
||||
bool UpdateValue(T& current_value, const T new_value) { |
|
||||
const bool changed = current_value != new_value; |
|
||||
current_value = new_value; |
|
||||
return changed; |
|
||||
} |
|
||||
|
|
||||
template <typename T1, typename T2> |
|
||||
bool UpdateTie(T1 current_value, const T2 new_value) { |
|
||||
const bool changed = current_value != new_value; |
|
||||
current_value = new_value; |
|
||||
return changed; |
|
||||
} |
|
||||
|
|
||||
template <typename T> |
|
||||
std::optional<std::pair<GLuint, GLsizei>> UpdateArray(T& current_values, const T& new_values) { |
|
||||
std::optional<std::size_t> first; |
|
||||
std::size_t last; |
|
||||
for (std::size_t i = 0; i < std::size(current_values); ++i) { |
|
||||
if (!UpdateValue(current_values[i], new_values[i])) { |
|
||||
continue; |
|
||||
} |
|
||||
if (!first) { |
|
||||
first = i; |
|
||||
} |
|
||||
last = i; |
|
||||
} |
|
||||
if (!first) { |
|
||||
return std::nullopt; |
|
||||
} |
|
||||
return std::make_pair(static_cast<GLuint>(*first), static_cast<GLsizei>(last - *first + 1)); |
|
||||
} |
|
||||
|
|
||||
void Enable(GLenum cap, bool enable) { |
|
||||
if (enable) { |
|
||||
glEnable(cap); |
|
||||
} else { |
|
||||
glDisable(cap); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void Enable(GLenum cap, GLuint index, bool enable) { |
|
||||
if (enable) { |
|
||||
glEnablei(cap, index); |
|
||||
} else { |
|
||||
glDisablei(cap, index); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void Enable(GLenum cap, bool& current_value, bool new_value) { |
|
||||
if (UpdateValue(current_value, new_value)) { |
|
||||
Enable(cap, new_value); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void Enable(GLenum cap, GLuint index, bool& current_value, bool new_value) { |
|
||||
if (UpdateValue(current_value, new_value)) { |
|
||||
Enable(cap, index, new_value); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
} // Anonymous namespace
|
|
||||
|
|
||||
OpenGLState::OpenGLState() = default; |
|
||||
|
|
||||
void OpenGLState::SetDefaultViewports() { |
|
||||
viewports.fill(Viewport{}); |
|
||||
|
|
||||
depth_clamp.far_plane = false; |
|
||||
depth_clamp.near_plane = false; |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyFramebufferState() { |
|
||||
if (UpdateValue(cur_state.draw.read_framebuffer, draw.read_framebuffer)) { |
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer); |
|
||||
} |
|
||||
if (UpdateValue(cur_state.draw.draw_framebuffer, draw.draw_framebuffer)) { |
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, draw.draw_framebuffer); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyVertexArrayState() { |
|
||||
if (UpdateValue(cur_state.draw.vertex_array, draw.vertex_array)) { |
|
||||
glBindVertexArray(draw.vertex_array); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyShaderProgram() { |
|
||||
if (UpdateValue(cur_state.draw.shader_program, draw.shader_program)) { |
|
||||
glUseProgram(draw.shader_program); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyProgramPipeline() { |
|
||||
if (UpdateValue(cur_state.draw.program_pipeline, draw.program_pipeline)) { |
|
||||
glBindProgramPipeline(draw.program_pipeline); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyClipDistances() { |
|
||||
for (std::size_t i = 0; i < clip_distance.size(); ++i) { |
|
||||
Enable(GL_CLIP_DISTANCE0 + static_cast<GLenum>(i), cur_state.clip_distance[i], |
|
||||
clip_distance[i]); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyPointSize() { |
|
||||
Enable(GL_PROGRAM_POINT_SIZE, cur_state.point.program_control, point.program_control); |
|
||||
Enable(GL_POINT_SPRITE, cur_state.point.sprite, point.sprite); |
|
||||
if (UpdateValue(cur_state.point.size, point.size)) { |
|
||||
glPointSize(point.size); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyFragmentColorClamp() { |
|
||||
if (UpdateValue(cur_state.fragment_color_clamp.enabled, fragment_color_clamp.enabled)) { |
|
||||
glClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB, |
|
||||
fragment_color_clamp.enabled ? GL_TRUE : GL_FALSE); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyMultisample() { |
|
||||
Enable(GL_SAMPLE_ALPHA_TO_COVERAGE, cur_state.multisample_control.alpha_to_coverage, |
|
||||
multisample_control.alpha_to_coverage); |
|
||||
Enable(GL_SAMPLE_ALPHA_TO_ONE, cur_state.multisample_control.alpha_to_one, |
|
||||
multisample_control.alpha_to_one); |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyDepthClamp() { |
|
||||
if (depth_clamp.far_plane == cur_state.depth_clamp.far_plane && |
|
||||
depth_clamp.near_plane == cur_state.depth_clamp.near_plane) { |
|
||||
return; |
|
||||
} |
|
||||
cur_state.depth_clamp = depth_clamp; |
|
||||
|
|
||||
UNIMPLEMENTED_IF_MSG(depth_clamp.far_plane != depth_clamp.near_plane, |
|
||||
"Unimplemented Depth Clamp Separation!"); |
|
||||
|
|
||||
Enable(GL_DEPTH_CLAMP, depth_clamp.far_plane || depth_clamp.near_plane); |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplySRgb() { |
|
||||
if (cur_state.framebuffer_srgb.enabled == framebuffer_srgb.enabled) |
|
||||
return; |
|
||||
cur_state.framebuffer_srgb.enabled = framebuffer_srgb.enabled; |
|
||||
if (framebuffer_srgb.enabled) { |
|
||||
glEnable(GL_FRAMEBUFFER_SRGB); |
|
||||
} else { |
|
||||
glDisable(GL_FRAMEBUFFER_SRGB); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyCulling() { |
|
||||
Enable(GL_CULL_FACE, cur_state.cull.enabled, cull.enabled); |
|
||||
|
|
||||
if (UpdateValue(cur_state.cull.mode, cull.mode)) { |
|
||||
glCullFace(cull.mode); |
|
||||
} |
|
||||
|
|
||||
if (UpdateValue(cur_state.cull.front_face, cull.front_face)) { |
|
||||
glFrontFace(cull.front_face); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyRasterizerDiscard() { |
|
||||
Enable(GL_RASTERIZER_DISCARD, cur_state.rasterizer_discard, rasterizer_discard); |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyColorMask() { |
|
||||
if (!dirty.color_mask) { |
|
||||
return; |
|
||||
} |
|
||||
dirty.color_mask = false; |
|
||||
|
|
||||
for (std::size_t i = 0; i < Maxwell::NumRenderTargets; ++i) { |
|
||||
const auto& updated = color_mask[i]; |
|
||||
auto& current = cur_state.color_mask[i]; |
|
||||
if (updated.red_enabled != current.red_enabled || |
|
||||
updated.green_enabled != current.green_enabled || |
|
||||
updated.blue_enabled != current.blue_enabled || |
|
||||
updated.alpha_enabled != current.alpha_enabled) { |
|
||||
current = updated; |
|
||||
glColorMaski(static_cast<GLuint>(i), updated.red_enabled, updated.green_enabled, |
|
||||
updated.blue_enabled, updated.alpha_enabled); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyDepth() { |
|
||||
Enable(GL_DEPTH_TEST, cur_state.depth.test_enabled, depth.test_enabled); |
|
||||
|
|
||||
if (cur_state.depth.test_func != depth.test_func) { |
|
||||
cur_state.depth.test_func = depth.test_func; |
|
||||
glDepthFunc(depth.test_func); |
|
||||
} |
|
||||
|
|
||||
if (cur_state.depth.write_mask != depth.write_mask) { |
|
||||
cur_state.depth.write_mask = depth.write_mask; |
|
||||
glDepthMask(depth.write_mask); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyPrimitiveRestart() { |
|
||||
Enable(GL_PRIMITIVE_RESTART, cur_state.primitive_restart.enabled, primitive_restart.enabled); |
|
||||
|
|
||||
if (cur_state.primitive_restart.index != primitive_restart.index) { |
|
||||
cur_state.primitive_restart.index = primitive_restart.index; |
|
||||
glPrimitiveRestartIndex(primitive_restart.index); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyStencilTest() { |
|
||||
if (!dirty.stencil_state) { |
|
||||
return; |
|
||||
} |
|
||||
dirty.stencil_state = false; |
|
||||
|
|
||||
Enable(GL_STENCIL_TEST, cur_state.stencil.test_enabled, stencil.test_enabled); |
|
||||
|
|
||||
const auto ConfigStencil = [](GLenum face, const auto& config, auto& current) { |
|
||||
if (current.test_func != config.test_func || current.test_ref != config.test_ref || |
|
||||
current.test_mask != config.test_mask) { |
|
||||
current.test_func = config.test_func; |
|
||||
current.test_ref = config.test_ref; |
|
||||
current.test_mask = config.test_mask; |
|
||||
glStencilFuncSeparate(face, config.test_func, config.test_ref, config.test_mask); |
|
||||
} |
|
||||
if (current.action_depth_fail != config.action_depth_fail || |
|
||||
current.action_depth_pass != config.action_depth_pass || |
|
||||
current.action_stencil_fail != config.action_stencil_fail) { |
|
||||
current.action_depth_fail = config.action_depth_fail; |
|
||||
current.action_depth_pass = config.action_depth_pass; |
|
||||
current.action_stencil_fail = config.action_stencil_fail; |
|
||||
glStencilOpSeparate(face, config.action_stencil_fail, config.action_depth_fail, |
|
||||
config.action_depth_pass); |
|
||||
} |
|
||||
if (current.write_mask != config.write_mask) { |
|
||||
current.write_mask = config.write_mask; |
|
||||
glStencilMaskSeparate(face, config.write_mask); |
|
||||
} |
|
||||
}; |
|
||||
ConfigStencil(GL_FRONT, stencil.front, cur_state.stencil.front); |
|
||||
ConfigStencil(GL_BACK, stencil.back, cur_state.stencil.back); |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyViewport() { |
|
||||
for (GLuint i = 0; i < static_cast<GLuint>(Maxwell::NumViewports); ++i) { |
|
||||
const auto& updated = viewports[i]; |
|
||||
auto& current = cur_state.viewports[i]; |
|
||||
|
|
||||
if (current.x != updated.x || current.y != updated.y || current.width != updated.width || |
|
||||
current.height != updated.height) { |
|
||||
current.x = updated.x; |
|
||||
current.y = updated.y; |
|
||||
current.width = updated.width; |
|
||||
current.height = updated.height; |
|
||||
glViewportIndexedf(i, static_cast<GLfloat>(updated.x), static_cast<GLfloat>(updated.y), |
|
||||
static_cast<GLfloat>(updated.width), |
|
||||
static_cast<GLfloat>(updated.height)); |
|
||||
} |
|
||||
if (current.depth_range_near != updated.depth_range_near || |
|
||||
current.depth_range_far != updated.depth_range_far) { |
|
||||
current.depth_range_near = updated.depth_range_near; |
|
||||
current.depth_range_far = updated.depth_range_far; |
|
||||
glDepthRangeIndexed(i, updated.depth_range_near, updated.depth_range_far); |
|
||||
} |
|
||||
|
|
||||
Enable(GL_SCISSOR_TEST, i, current.scissor.enabled, updated.scissor.enabled); |
|
||||
|
|
||||
if (current.scissor.x != updated.scissor.x || current.scissor.y != updated.scissor.y || |
|
||||
current.scissor.width != updated.scissor.width || |
|
||||
current.scissor.height != updated.scissor.height) { |
|
||||
current.scissor.x = updated.scissor.x; |
|
||||
current.scissor.y = updated.scissor.y; |
|
||||
current.scissor.width = updated.scissor.width; |
|
||||
current.scissor.height = updated.scissor.height; |
|
||||
glScissorIndexed(i, updated.scissor.x, updated.scissor.y, updated.scissor.width, |
|
||||
updated.scissor.height); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyGlobalBlending() { |
|
||||
const Blend& updated = blend[0]; |
|
||||
Blend& current = cur_state.blend[0]; |
|
||||
|
|
||||
Enable(GL_BLEND, current.enabled, updated.enabled); |
|
||||
|
|
||||
if (current.src_rgb_func != updated.src_rgb_func || |
|
||||
current.dst_rgb_func != updated.dst_rgb_func || current.src_a_func != updated.src_a_func || |
|
||||
current.dst_a_func != updated.dst_a_func) { |
|
||||
current.src_rgb_func = updated.src_rgb_func; |
|
||||
current.dst_rgb_func = updated.dst_rgb_func; |
|
||||
current.src_a_func = updated.src_a_func; |
|
||||
current.dst_a_func = updated.dst_a_func; |
|
||||
glBlendFuncSeparate(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func, |
|
||||
updated.dst_a_func); |
|
||||
} |
|
||||
|
|
||||
if (current.rgb_equation != updated.rgb_equation || current.a_equation != updated.a_equation) { |
|
||||
current.rgb_equation = updated.rgb_equation; |
|
||||
current.a_equation = updated.a_equation; |
|
||||
glBlendEquationSeparate(updated.rgb_equation, updated.a_equation); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) { |
|
||||
const Blend& updated = blend[target]; |
|
||||
Blend& current = cur_state.blend[target]; |
|
||||
|
|
||||
if (current.enabled != updated.enabled || force) { |
|
||||
current.enabled = updated.enabled; |
|
||||
Enable(GL_BLEND, static_cast<GLuint>(target), updated.enabled); |
|
||||
} |
|
||||
|
|
||||
if (UpdateTie(std::tie(current.src_rgb_func, current.dst_rgb_func, current.src_a_func, |
|
||||
current.dst_a_func), |
|
||||
std::tie(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func, |
|
||||
updated.dst_a_func))) { |
|
||||
glBlendFuncSeparatei(static_cast<GLuint>(target), updated.src_rgb_func, |
|
||||
updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func); |
|
||||
} |
|
||||
|
|
||||
if (UpdateTie(std::tie(current.rgb_equation, current.a_equation), |
|
||||
std::tie(updated.rgb_equation, updated.a_equation))) { |
|
||||
glBlendEquationSeparatei(static_cast<GLuint>(target), updated.rgb_equation, |
|
||||
updated.a_equation); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyBlending() { |
|
||||
if (!dirty.blend_state) { |
|
||||
return; |
|
||||
} |
|
||||
dirty.blend_state = false; |
|
||||
|
|
||||
if (independant_blend.enabled) { |
|
||||
const bool force = independant_blend.enabled != cur_state.independant_blend.enabled; |
|
||||
for (std::size_t target = 0; target < Maxwell::NumRenderTargets; ++target) { |
|
||||
ApplyTargetBlending(target, force); |
|
||||
} |
|
||||
} else { |
|
||||
ApplyGlobalBlending(); |
|
||||
} |
|
||||
cur_state.independant_blend.enabled = independant_blend.enabled; |
|
||||
|
|
||||
if (UpdateTie( |
|
||||
std::tie(cur_state.blend_color.red, cur_state.blend_color.green, |
|
||||
cur_state.blend_color.blue, cur_state.blend_color.alpha), |
|
||||
std::tie(blend_color.red, blend_color.green, blend_color.blue, blend_color.alpha))) { |
|
||||
glBlendColor(blend_color.red, blend_color.green, blend_color.blue, blend_color.alpha); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyLogicOp() { |
|
||||
Enable(GL_COLOR_LOGIC_OP, cur_state.logic_op.enabled, logic_op.enabled); |
|
||||
|
|
||||
if (UpdateValue(cur_state.logic_op.operation, logic_op.operation)) { |
|
||||
glLogicOp(logic_op.operation); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyPolygonOffset() { |
|
||||
if (!dirty.polygon_offset) { |
|
||||
return; |
|
||||
} |
|
||||
dirty.polygon_offset = false; |
|
||||
|
|
||||
Enable(GL_POLYGON_OFFSET_FILL, cur_state.polygon_offset.fill_enable, |
|
||||
polygon_offset.fill_enable); |
|
||||
Enable(GL_POLYGON_OFFSET_LINE, cur_state.polygon_offset.line_enable, |
|
||||
polygon_offset.line_enable); |
|
||||
Enable(GL_POLYGON_OFFSET_POINT, cur_state.polygon_offset.point_enable, |
|
||||
polygon_offset.point_enable); |
|
||||
|
|
||||
if (UpdateTie(std::tie(cur_state.polygon_offset.factor, cur_state.polygon_offset.units, |
|
||||
cur_state.polygon_offset.clamp), |
|
||||
std::tie(polygon_offset.factor, polygon_offset.units, polygon_offset.clamp))) { |
|
||||
if (GLAD_GL_EXT_polygon_offset_clamp && polygon_offset.clamp != 0) { |
|
||||
glPolygonOffsetClamp(polygon_offset.factor, polygon_offset.units, polygon_offset.clamp); |
|
||||
} else { |
|
||||
UNIMPLEMENTED_IF_MSG(polygon_offset.clamp != 0, |
|
||||
"Unimplemented Depth polygon offset clamp."); |
|
||||
glPolygonOffset(polygon_offset.factor, polygon_offset.units); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyAlphaTest() { |
|
||||
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::ApplyClipControl() { |
|
||||
if (UpdateTie(std::tie(cur_state.clip_control.origin, cur_state.clip_control.depth_mode), |
|
||||
std::tie(clip_control.origin, clip_control.depth_mode))) { |
|
||||
glClipControl(clip_control.origin, clip_control.depth_mode); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyRenderBuffer() { |
|
||||
if (cur_state.renderbuffer != renderbuffer) { |
|
||||
cur_state.renderbuffer = renderbuffer; |
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyTextures() { |
|
||||
const std::size_t size = std::size(textures); |
|
||||
for (std::size_t i = 0; i < size; ++i) { |
|
||||
if (UpdateValue(cur_state.textures[i], textures[i])) { |
|
||||
// BindTextureUnit doesn't support binding null textures, skip those binds.
|
|
||||
// TODO(Rodrigo): Stop using null textures
|
|
||||
if (textures[i] != 0) { |
|
||||
glBindTextureUnit(static_cast<GLuint>(i), textures[i]); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplySamplers() { |
|
||||
const std::size_t size = std::size(samplers); |
|
||||
for (std::size_t i = 0; i < size; ++i) { |
|
||||
if (UpdateValue(cur_state.samplers[i], samplers[i])) { |
|
||||
glBindSampler(static_cast<GLuint>(i), samplers[i]); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::ApplyImages() { |
|
||||
if (const auto update = UpdateArray(cur_state.images, images)) { |
|
||||
glBindImageTextures(update->first, update->second, images.data() + update->first); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::Apply() { |
|
||||
MICROPROFILE_SCOPE(OpenGL_State); |
|
||||
ApplyFramebufferState(); |
|
||||
ApplyVertexArrayState(); |
|
||||
ApplyShaderProgram(); |
|
||||
ApplyProgramPipeline(); |
|
||||
ApplyClipDistances(); |
|
||||
ApplyPointSize(); |
|
||||
ApplyFragmentColorClamp(); |
|
||||
ApplyMultisample(); |
|
||||
ApplyRasterizerDiscard(); |
|
||||
ApplyColorMask(); |
|
||||
ApplyDepthClamp(); |
|
||||
ApplyViewport(); |
|
||||
ApplyStencilTest(); |
|
||||
ApplySRgb(); |
|
||||
ApplyCulling(); |
|
||||
ApplyDepth(); |
|
||||
ApplyPrimitiveRestart(); |
|
||||
ApplyBlending(); |
|
||||
ApplyLogicOp(); |
|
||||
ApplyTextures(); |
|
||||
ApplySamplers(); |
|
||||
ApplyImages(); |
|
||||
ApplyPolygonOffset(); |
|
||||
ApplyAlphaTest(); |
|
||||
ApplyClipControl(); |
|
||||
ApplyRenderBuffer(); |
|
||||
} |
|
||||
|
|
||||
void OpenGLState::EmulateViewportWithScissor() { |
|
||||
auto& current = viewports[0]; |
|
||||
if (current.scissor.enabled) { |
|
||||
const GLint left = std::max(current.x, current.scissor.x); |
|
||||
const GLint right = |
|
||||
std::max(current.x + current.width, current.scissor.x + current.scissor.width); |
|
||||
const GLint bottom = std::max(current.y, current.scissor.y); |
|
||||
const GLint top = |
|
||||
std::max(current.y + current.height, current.scissor.y + current.scissor.height); |
|
||||
current.scissor.x = std::max(left, 0); |
|
||||
current.scissor.y = std::max(bottom, 0); |
|
||||
current.scissor.width = std::max(right - left, 0); |
|
||||
current.scissor.height = std::max(top - bottom, 0); |
|
||||
} else { |
|
||||
current.scissor.enabled = true; |
|
||||
current.scissor.x = current.x; |
|
||||
current.scissor.y = current.y; |
|
||||
current.scissor.width = current.width; |
|
||||
current.scissor.height = current.height; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
OpenGLState& OpenGLState::UnbindTexture(GLuint handle) { |
|
||||
for (auto& texture : textures) { |
|
||||
if (texture == handle) { |
|
||||
texture = 0; |
|
||||
} |
|
||||
} |
|
||||
return *this; |
|
||||
} |
|
||||
|
|
||||
OpenGLState& OpenGLState::ResetSampler(GLuint handle) { |
|
||||
for (auto& sampler : samplers) { |
|
||||
if (sampler == handle) { |
|
||||
sampler = 0; |
|
||||
} |
|
||||
} |
|
||||
return *this; |
|
||||
} |
|
||||
|
|
||||
OpenGLState& OpenGLState::ResetProgram(GLuint handle) { |
|
||||
if (draw.shader_program == handle) { |
|
||||
draw.shader_program = 0; |
|
||||
} |
|
||||
return *this; |
|
||||
} |
|
||||
|
|
||||
OpenGLState& OpenGLState::ResetPipeline(GLuint handle) { |
|
||||
if (draw.program_pipeline == handle) { |
|
||||
draw.program_pipeline = 0; |
|
||||
} |
|
||||
return *this; |
|
||||
} |
|
||||
|
|
||||
OpenGLState& OpenGLState::ResetVertexArray(GLuint handle) { |
|
||||
if (draw.vertex_array == handle) { |
|
||||
draw.vertex_array = 0; |
|
||||
} |
|
||||
return *this; |
|
||||
} |
|
||||
|
|
||||
OpenGLState& OpenGLState::ResetFramebuffer(GLuint handle) { |
|
||||
if (draw.read_framebuffer == handle) { |
|
||||
draw.read_framebuffer = 0; |
|
||||
} |
|
||||
if (draw.draw_framebuffer == handle) { |
|
||||
draw.draw_framebuffer = 0; |
|
||||
} |
|
||||
return *this; |
|
||||
} |
|
||||
|
|
||||
OpenGLState& OpenGLState::ResetRenderbuffer(GLuint handle) { |
|
||||
if (renderbuffer == handle) { |
|
||||
renderbuffer = 0; |
|
||||
} |
|
||||
return *this; |
|
||||
} |
|
||||
|
|
||||
} // namespace OpenGL
|
|
||||
@ -1,251 +0,0 @@ |
|||||
// Copyright 2015 Citra Emulator Project |
|
||||
// Licensed under GPLv2 or any later version |
|
||||
// Refer to the license.txt file included. |
|
||||
|
|
||||
#pragma once |
|
||||
|
|
||||
#include <array> |
|
||||
#include <type_traits> |
|
||||
#include <glad/glad.h> |
|
||||
#include "video_core/engines/maxwell_3d.h" |
|
||||
|
|
||||
namespace OpenGL { |
|
||||
|
|
||||
class OpenGLState { |
|
||||
public: |
|
||||
struct { |
|
||||
bool enabled = false; // GL_FRAMEBUFFER_SRGB |
|
||||
} framebuffer_srgb; |
|
||||
|
|
||||
struct { |
|
||||
bool alpha_to_coverage = false; // GL_ALPHA_TO_COVERAGE |
|
||||
bool alpha_to_one = false; // GL_ALPHA_TO_ONE |
|
||||
} multisample_control; |
|
||||
|
|
||||
struct { |
|
||||
bool enabled = false; // GL_CLAMP_FRAGMENT_COLOR_ARB |
|
||||
} fragment_color_clamp; |
|
||||
|
|
||||
struct { |
|
||||
bool far_plane = false; |
|
||||
bool near_plane = false; |
|
||||
} depth_clamp; // GL_DEPTH_CLAMP |
|
||||
|
|
||||
struct { |
|
||||
bool enabled = false; // GL_CULL_FACE |
|
||||
GLenum mode = GL_BACK; // GL_CULL_FACE_MODE |
|
||||
GLenum front_face = GL_CCW; // GL_FRONT_FACE |
|
||||
} cull; |
|
||||
|
|
||||
struct { |
|
||||
bool test_enabled = false; // GL_DEPTH_TEST |
|
||||
GLboolean write_mask = GL_TRUE; // GL_DEPTH_WRITEMASK |
|
||||
GLenum test_func = GL_LESS; // GL_DEPTH_FUNC |
|
||||
} depth; |
|
||||
|
|
||||
struct { |
|
||||
bool enabled = false; |
|
||||
GLuint index = 0; |
|
||||
} primitive_restart; // GL_PRIMITIVE_RESTART |
|
||||
|
|
||||
bool rasterizer_discard = false; // GL_RASTERIZER_DISCARD |
|
||||
|
|
||||
struct ColorMask { |
|
||||
GLboolean red_enabled = GL_TRUE; |
|
||||
GLboolean green_enabled = GL_TRUE; |
|
||||
GLboolean blue_enabled = GL_TRUE; |
|
||||
GLboolean alpha_enabled = GL_TRUE; |
|
||||
}; |
|
||||
std::array<ColorMask, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> |
|
||||
color_mask; // GL_COLOR_WRITEMASK |
|
||||
|
|
||||
struct { |
|
||||
bool test_enabled = false; // GL_STENCIL_TEST |
|
||||
struct { |
|
||||
GLenum test_func = GL_ALWAYS; // GL_STENCIL_FUNC |
|
||||
GLint test_ref = 0; // GL_STENCIL_REF |
|
||||
GLuint test_mask = 0xFFFFFFFF; // GL_STENCIL_VALUE_MASK |
|
||||
GLuint write_mask = 0xFFFFFFFF; // GL_STENCIL_WRITEMASK |
|
||||
GLenum action_stencil_fail = GL_KEEP; // GL_STENCIL_FAIL |
|
||||
GLenum action_depth_fail = GL_KEEP; // GL_STENCIL_PASS_DEPTH_FAIL |
|
||||
GLenum action_depth_pass = GL_KEEP; // GL_STENCIL_PASS_DEPTH_PASS |
|
||||
} front, back; |
|
||||
} stencil; |
|
||||
|
|
||||
struct Blend { |
|
||||
bool enabled = false; // GL_BLEND |
|
||||
GLenum rgb_equation = GL_FUNC_ADD; // GL_BLEND_EQUATION_RGB |
|
||||
GLenum a_equation = GL_FUNC_ADD; // GL_BLEND_EQUATION_ALPHA |
|
||||
GLenum src_rgb_func = GL_ONE; // GL_BLEND_SRC_RGB |
|
||||
GLenum dst_rgb_func = GL_ZERO; // GL_BLEND_DST_RGB |
|
||||
GLenum src_a_func = GL_ONE; // GL_BLEND_SRC_ALPHA |
|
||||
GLenum dst_a_func = GL_ZERO; // GL_BLEND_DST_ALPHA |
|
||||
}; |
|
||||
std::array<Blend, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> blend; |
|
||||
|
|
||||
struct { |
|
||||
bool enabled = false; |
|
||||
} independant_blend; |
|
||||
|
|
||||
struct { |
|
||||
GLclampf red = 0.0f; |
|
||||
GLclampf green = 0.0f; |
|
||||
GLclampf blue = 0.0f; |
|
||||
GLclampf alpha = 0.0f; |
|
||||
} blend_color; // GL_BLEND_COLOR |
|
||||
|
|
||||
struct { |
|
||||
bool enabled = false; // GL_LOGIC_OP_MODE |
|
||||
GLenum operation = GL_COPY; |
|
||||
} logic_op; |
|
||||
|
|
||||
static constexpr std::size_t NumSamplers = 32 * 5; |
|
||||
static constexpr std::size_t NumImages = 8 * 5; |
|
||||
std::array<GLuint, NumSamplers> textures = {}; |
|
||||
std::array<GLuint, NumSamplers> samplers = {}; |
|
||||
std::array<GLuint, NumImages> images = {}; |
|
||||
|
|
||||
struct { |
|
||||
GLuint read_framebuffer = 0; // GL_READ_FRAMEBUFFER_BINDING |
|
||||
GLuint draw_framebuffer = 0; // GL_DRAW_FRAMEBUFFER_BINDING |
|
||||
GLuint vertex_array = 0; // GL_VERTEX_ARRAY_BINDING |
|
||||
GLuint shader_program = 0; // GL_CURRENT_PROGRAM |
|
||||
GLuint program_pipeline = 0; // GL_PROGRAM_PIPELINE_BINDING |
|
||||
} draw; |
|
||||
|
|
||||
struct Viewport { |
|
||||
GLint x = 0; |
|
||||
GLint y = 0; |
|
||||
GLint width = 0; |
|
||||
GLint height = 0; |
|
||||
GLfloat depth_range_near = 0.0f; // GL_DEPTH_RANGE |
|
||||
GLfloat depth_range_far = 1.0f; // GL_DEPTH_RANGE |
|
||||
struct { |
|
||||
bool enabled = false; // GL_SCISSOR_TEST |
|
||||
GLint x = 0; |
|
||||
GLint y = 0; |
|
||||
GLsizei width = 0; |
|
||||
GLsizei height = 0; |
|
||||
} scissor; |
|
||||
}; |
|
||||
std::array<Viewport, Tegra::Engines::Maxwell3D::Regs::NumViewports> viewports; |
|
||||
|
|
||||
struct { |
|
||||
bool program_control = false; // GL_PROGRAM_POINT_SIZE |
|
||||
bool sprite = false; // GL_POINT_SPRITE |
|
||||
GLfloat size = 1.0f; // GL_POINT_SIZE |
|
||||
} point; |
|
||||
|
|
||||
struct { |
|
||||
bool point_enable = false; |
|
||||
bool line_enable = false; |
|
||||
bool fill_enable = false; |
|
||||
GLfloat units = 0.0f; |
|
||||
GLfloat factor = 0.0f; |
|
||||
GLfloat clamp = 0.0f; |
|
||||
} polygon_offset; |
|
||||
|
|
||||
struct { |
|
||||
bool enabled = false; // GL_ALPHA_TEST |
|
||||
GLenum func = GL_ALWAYS; // GL_ALPHA_TEST_FUNC |
|
||||
GLfloat ref = 0.0f; // GL_ALPHA_TEST_REF |
|
||||
} alpha_test; |
|
||||
|
|
||||
std::array<bool, 8> clip_distance = {}; // GL_CLIP_DISTANCE |
|
||||
|
|
||||
struct { |
|
||||
GLenum origin = GL_LOWER_LEFT; |
|
||||
GLenum depth_mode = GL_NEGATIVE_ONE_TO_ONE; |
|
||||
} clip_control; |
|
||||
|
|
||||
GLuint renderbuffer{}; // GL_RENDERBUFFER_BINDING |
|
||||
|
|
||||
OpenGLState(); |
|
||||
|
|
||||
/// Get the currently active OpenGL state |
|
||||
static OpenGLState GetCurState() { |
|
||||
return cur_state; |
|
||||
} |
|
||||
|
|
||||
void SetDefaultViewports(); |
|
||||
/// Apply this state as the current OpenGL state |
|
||||
void Apply(); |
|
||||
|
|
||||
void ApplyFramebufferState(); |
|
||||
void ApplyVertexArrayState(); |
|
||||
void ApplyShaderProgram(); |
|
||||
void ApplyProgramPipeline(); |
|
||||
void ApplyClipDistances(); |
|
||||
void ApplyPointSize(); |
|
||||
void ApplyFragmentColorClamp(); |
|
||||
void ApplyMultisample(); |
|
||||
void ApplySRgb(); |
|
||||
void ApplyCulling(); |
|
||||
void ApplyRasterizerDiscard(); |
|
||||
void ApplyColorMask(); |
|
||||
void ApplyDepth(); |
|
||||
void ApplyPrimitiveRestart(); |
|
||||
void ApplyStencilTest(); |
|
||||
void ApplyViewport(); |
|
||||
void ApplyTargetBlending(std::size_t target, bool force); |
|
||||
void ApplyGlobalBlending(); |
|
||||
void ApplyBlending(); |
|
||||
void ApplyLogicOp(); |
|
||||
void ApplyTextures(); |
|
||||
void ApplySamplers(); |
|
||||
void ApplyImages(); |
|
||||
void ApplyDepthClamp(); |
|
||||
void ApplyPolygonOffset(); |
|
||||
void ApplyAlphaTest(); |
|
||||
void ApplyClipControl(); |
|
||||
void ApplyRenderBuffer(); |
|
||||
|
|
||||
/// Resets any references to the given resource |
|
||||
OpenGLState& UnbindTexture(GLuint handle); |
|
||||
OpenGLState& ResetSampler(GLuint handle); |
|
||||
OpenGLState& ResetProgram(GLuint handle); |
|
||||
OpenGLState& ResetPipeline(GLuint handle); |
|
||||
OpenGLState& ResetVertexArray(GLuint handle); |
|
||||
OpenGLState& ResetFramebuffer(GLuint handle); |
|
||||
OpenGLState& ResetRenderbuffer(GLuint handle); |
|
||||
|
|
||||
/// Viewport does not affects glClearBuffer so emulate viewport using scissor test |
|
||||
void EmulateViewportWithScissor(); |
|
||||
|
|
||||
void MarkDirtyBlendState() { |
|
||||
dirty.blend_state = true; |
|
||||
} |
|
||||
|
|
||||
void MarkDirtyStencilState() { |
|
||||
dirty.stencil_state = true; |
|
||||
} |
|
||||
|
|
||||
void MarkDirtyPolygonOffset() { |
|
||||
dirty.polygon_offset = true; |
|
||||
} |
|
||||
|
|
||||
void MarkDirtyColorMask() { |
|
||||
dirty.color_mask = true; |
|
||||
} |
|
||||
|
|
||||
void AllDirty() { |
|
||||
dirty.blend_state = true; |
|
||||
dirty.stencil_state = true; |
|
||||
dirty.polygon_offset = true; |
|
||||
dirty.color_mask = true; |
|
||||
} |
|
||||
|
|
||||
private: |
|
||||
static OpenGLState cur_state; |
|
||||
|
|
||||
struct { |
|
||||
bool blend_state; |
|
||||
bool stencil_state; |
|
||||
bool viewport_state; |
|
||||
bool polygon_offset; |
|
||||
bool color_mask; |
|
||||
} dirty{}; |
|
||||
}; |
|
||||
static_assert(std::is_trivially_copyable_v<OpenGLState>); |
|
||||
|
|
||||
} // namespace OpenGL |
|
||||
@ -0,0 +1,238 @@ |
|||||
|
// Copyright 2019 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include <algorithm>
|
||||
|
#include <array>
|
||||
|
#include <cstddef>
|
||||
|
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "core/core.h"
|
||||
|
#include "video_core/engines/maxwell_3d.h"
|
||||
|
#include "video_core/gpu.h"
|
||||
|
#include "video_core/renderer_opengl/gl_state_tracker.h"
|
||||
|
|
||||
|
#define OFF(field_name) MAXWELL3D_REG_INDEX(field_name)
|
||||
|
#define NUM(field_name) (sizeof(Maxwell3D::Regs::field_name) / sizeof(u32))
|
||||
|
|
||||
|
namespace OpenGL { |
||||
|
|
||||
|
namespace { |
||||
|
|
||||
|
using namespace Dirty; |
||||
|
using namespace VideoCommon::Dirty; |
||||
|
using Tegra::Engines::Maxwell3D; |
||||
|
using Regs = Maxwell3D::Regs; |
||||
|
using Tables = Maxwell3D::DirtyState::Tables; |
||||
|
using Table = Maxwell3D::DirtyState::Table; |
||||
|
|
||||
|
void SetupDirtyColorMasks(Tables& tables) { |
||||
|
tables[0][OFF(color_mask_common)] = ColorMaskCommon; |
||||
|
for (std::size_t rt = 0; rt < Regs::NumRenderTargets; ++rt) { |
||||
|
const std::size_t offset = OFF(color_mask) + rt * NUM(color_mask[0]); |
||||
|
FillBlock(tables[0], offset, NUM(color_mask[0]), ColorMask0 + rt); |
||||
|
} |
||||
|
|
||||
|
FillBlock(tables[1], OFF(color_mask), NUM(color_mask), ColorMasks); |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyVertexArrays(Tables& tables) { |
||||
|
static constexpr std::size_t num_array = 3; |
||||
|
static constexpr std::size_t instance_base_offset = 3; |
||||
|
for (std::size_t i = 0; i < Regs::NumVertexArrays; ++i) { |
||||
|
const std::size_t array_offset = OFF(vertex_array) + i * NUM(vertex_array[0]); |
||||
|
const std::size_t limit_offset = OFF(vertex_array_limit) + i * NUM(vertex_array_limit[0]); |
||||
|
|
||||
|
FillBlock(tables, array_offset, num_array, VertexBuffer0 + i, VertexBuffers); |
||||
|
FillBlock(tables, limit_offset, NUM(vertex_array_limit), VertexBuffer0 + i, VertexBuffers); |
||||
|
|
||||
|
const std::size_t instance_array_offset = array_offset + instance_base_offset; |
||||
|
tables[0][instance_array_offset] = static_cast<u8>(VertexInstance0 + i); |
||||
|
tables[1][instance_array_offset] = VertexInstances; |
||||
|
|
||||
|
const std::size_t instance_offset = OFF(instanced_arrays) + i; |
||||
|
tables[0][instance_offset] = static_cast<u8>(VertexInstance0 + i); |
||||
|
tables[1][instance_offset] = VertexInstances; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyVertexFormat(Tables& tables) { |
||||
|
for (std::size_t i = 0; i < Regs::NumVertexAttributes; ++i) { |
||||
|
const std::size_t offset = OFF(vertex_attrib_format) + i * NUM(vertex_attrib_format[0]); |
||||
|
FillBlock(tables[0], offset, NUM(vertex_attrib_format[0]), VertexFormat0 + i); |
||||
|
} |
||||
|
|
||||
|
FillBlock(tables[1], OFF(vertex_attrib_format), Regs::NumVertexAttributes, VertexFormats); |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyViewports(Tables& tables) { |
||||
|
for (std::size_t i = 0; i < Regs::NumViewports; ++i) { |
||||
|
const std::size_t transf_offset = OFF(viewport_transform) + i * NUM(viewport_transform[0]); |
||||
|
const std::size_t viewport_offset = OFF(viewports) + i * NUM(viewports[0]); |
||||
|
|
||||
|
FillBlock(tables[0], transf_offset, NUM(viewport_transform[0]), Viewport0 + i); |
||||
|
FillBlock(tables[0], viewport_offset, NUM(viewports[0]), Viewport0 + i); |
||||
|
} |
||||
|
|
||||
|
FillBlock(tables[1], OFF(viewport_transform), NUM(viewport_transform), Viewports); |
||||
|
FillBlock(tables[1], OFF(viewports), NUM(viewports), Viewports); |
||||
|
|
||||
|
tables[0][OFF(viewport_transform_enabled)] = ViewportTransform; |
||||
|
tables[1][OFF(viewport_transform_enabled)] = Viewports; |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyScissors(Tables& tables) { |
||||
|
for (std::size_t i = 0; i < Regs::NumViewports; ++i) { |
||||
|
const std::size_t offset = OFF(scissor_test) + i * NUM(scissor_test[0]); |
||||
|
FillBlock(tables[0], offset, NUM(scissor_test[0]), Scissor0 + i); |
||||
|
} |
||||
|
FillBlock(tables[1], OFF(scissor_test), NUM(scissor_test), Scissors); |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyShaders(Tables& tables) { |
||||
|
FillBlock(tables[0], OFF(shader_config[0]), NUM(shader_config[0]) * Regs::MaxShaderProgram, |
||||
|
Shaders); |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyDepthTest(Tables& tables) { |
||||
|
auto& table = tables[0]; |
||||
|
table[OFF(depth_test_enable)] = DepthTest; |
||||
|
table[OFF(depth_write_enabled)] = DepthMask; |
||||
|
table[OFF(depth_test_func)] = DepthTest; |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyStencilTest(Tables& tables) { |
||||
|
static constexpr std::array offsets = { |
||||
|
OFF(stencil_enable), OFF(stencil_front_func_func), OFF(stencil_front_func_ref), |
||||
|
OFF(stencil_front_func_mask), OFF(stencil_front_op_fail), OFF(stencil_front_op_zfail), |
||||
|
OFF(stencil_front_op_zpass), OFF(stencil_front_mask), OFF(stencil_two_side_enable), |
||||
|
OFF(stencil_back_func_func), OFF(stencil_back_func_ref), OFF(stencil_back_func_mask), |
||||
|
OFF(stencil_back_op_fail), OFF(stencil_back_op_zfail), OFF(stencil_back_op_zpass), |
||||
|
OFF(stencil_back_mask)}; |
||||
|
for (const auto offset : offsets) { |
||||
|
tables[0][offset] = StencilTest; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyAlphaTest(Tables& tables) { |
||||
|
auto& table = tables[0]; |
||||
|
table[OFF(alpha_test_ref)] = AlphaTest; |
||||
|
table[OFF(alpha_test_func)] = AlphaTest; |
||||
|
table[OFF(alpha_test_enabled)] = AlphaTest; |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyBlend(Tables& tables) { |
||||
|
FillBlock(tables[0], OFF(blend_color), NUM(blend_color), BlendColor); |
||||
|
|
||||
|
tables[0][OFF(independent_blend_enable)] = BlendIndependentEnabled; |
||||
|
|
||||
|
for (std::size_t i = 0; i < Regs::NumRenderTargets; ++i) { |
||||
|
const std::size_t offset = OFF(independent_blend) + i * NUM(independent_blend[0]); |
||||
|
FillBlock(tables[0], offset, NUM(independent_blend[0]), BlendState0 + i); |
||||
|
|
||||
|
tables[0][OFF(blend.enable) + i] = static_cast<u8>(BlendState0 + i); |
||||
|
} |
||||
|
FillBlock(tables[1], OFF(independent_blend), NUM(independent_blend), BlendStates); |
||||
|
FillBlock(tables[1], OFF(blend), NUM(blend), BlendStates); |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyPrimitiveRestart(Tables& tables) { |
||||
|
FillBlock(tables[0], OFF(primitive_restart), NUM(primitive_restart), PrimitiveRestart); |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyPolygonOffset(Tables& tables) { |
||||
|
auto& table = tables[0]; |
||||
|
table[OFF(polygon_offset_fill_enable)] = PolygonOffset; |
||||
|
table[OFF(polygon_offset_line_enable)] = PolygonOffset; |
||||
|
table[OFF(polygon_offset_point_enable)] = PolygonOffset; |
||||
|
table[OFF(polygon_offset_factor)] = PolygonOffset; |
||||
|
table[OFF(polygon_offset_units)] = PolygonOffset; |
||||
|
table[OFF(polygon_offset_clamp)] = PolygonOffset; |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyMultisampleControl(Tables& tables) { |
||||
|
FillBlock(tables[0], OFF(multisample_control), NUM(multisample_control), MultisampleControl); |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyRasterizeEnable(Tables& tables) { |
||||
|
tables[0][OFF(rasterize_enable)] = RasterizeEnable; |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyFramebufferSRGB(Tables& tables) { |
||||
|
tables[0][OFF(framebuffer_srgb)] = FramebufferSRGB; |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyLogicOp(Tables& tables) { |
||||
|
FillBlock(tables[0], OFF(logic_op), NUM(logic_op), LogicOp); |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyFragmentClampColor(Tables& tables) { |
||||
|
tables[0][OFF(frag_color_clamp)] = FragmentClampColor; |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyPointSize(Tables& tables) { |
||||
|
tables[0][OFF(vp_point_size)] = PointSize; |
||||
|
tables[0][OFF(point_size)] = PointSize; |
||||
|
tables[0][OFF(point_sprite_enable)] = PointSize; |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyClipControl(Tables& tables) { |
||||
|
auto& table = tables[0]; |
||||
|
table[OFF(screen_y_control)] = ClipControl; |
||||
|
table[OFF(depth_mode)] = ClipControl; |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyDepthClampEnabled(Tables& tables) { |
||||
|
tables[0][OFF(view_volume_clip_control)] = DepthClampEnabled; |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyMisc(Tables& tables) { |
||||
|
auto& table = tables[0]; |
||||
|
|
||||
|
table[OFF(clip_distance_enabled)] = ClipDistances; |
||||
|
|
||||
|
table[OFF(front_face)] = FrontFace; |
||||
|
|
||||
|
table[OFF(cull_test_enabled)] = CullTest; |
||||
|
table[OFF(cull_face)] = CullTest; |
||||
|
} |
||||
|
|
||||
|
} // Anonymous namespace
|
||||
|
|
||||
|
StateTracker::StateTracker(Core::System& system) : system{system} {} |
||||
|
|
||||
|
void StateTracker::Initialize() { |
||||
|
auto& dirty = system.GPU().Maxwell3D().dirty; |
||||
|
auto& tables = dirty.tables; |
||||
|
SetupDirtyRenderTargets(tables); |
||||
|
SetupDirtyColorMasks(tables); |
||||
|
SetupDirtyViewports(tables); |
||||
|
SetupDirtyScissors(tables); |
||||
|
SetupDirtyVertexArrays(tables); |
||||
|
SetupDirtyVertexFormat(tables); |
||||
|
SetupDirtyShaders(tables); |
||||
|
SetupDirtyDepthTest(tables); |
||||
|
SetupDirtyStencilTest(tables); |
||||
|
SetupDirtyAlphaTest(tables); |
||||
|
SetupDirtyBlend(tables); |
||||
|
SetupDirtyPrimitiveRestart(tables); |
||||
|
SetupDirtyPolygonOffset(tables); |
||||
|
SetupDirtyMultisampleControl(tables); |
||||
|
SetupDirtyRasterizeEnable(tables); |
||||
|
SetupDirtyFramebufferSRGB(tables); |
||||
|
SetupDirtyLogicOp(tables); |
||||
|
SetupDirtyFragmentClampColor(tables); |
||||
|
SetupDirtyPointSize(tables); |
||||
|
SetupDirtyClipControl(tables); |
||||
|
SetupDirtyDepthClampEnabled(tables); |
||||
|
SetupDirtyMisc(tables); |
||||
|
|
||||
|
auto& store = dirty.on_write_stores; |
||||
|
SetupCommonOnWriteStores(store); |
||||
|
store[VertexBuffers] = true; |
||||
|
for (std::size_t i = 0; i < Regs::NumVertexArrays; ++i) { |
||||
|
store[VertexBuffer0 + i] = true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} // namespace OpenGL
|
||||
@ -0,0 +1,204 @@ |
|||||
|
// Copyright 2019 yuzu Emulator Project |
||||
|
// Licensed under GPLv2 or any later version |
||||
|
// Refer to the license.txt file included. |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <limits> |
||||
|
|
||||
|
#include <glad/glad.h> |
||||
|
|
||||
|
#include "common/common_types.h" |
||||
|
#include "core/core.h" |
||||
|
#include "video_core/dirty_flags.h" |
||||
|
#include "video_core/engines/maxwell_3d.h" |
||||
|
|
||||
|
namespace Core { |
||||
|
class System; |
||||
|
} |
||||
|
|
||||
|
namespace OpenGL { |
||||
|
|
||||
|
namespace Dirty { |
||||
|
|
||||
|
enum : u8 { |
||||
|
First = VideoCommon::Dirty::LastCommonEntry, |
||||
|
|
||||
|
VertexFormats, |
||||
|
VertexFormat0, |
||||
|
VertexFormat31 = VertexFormat0 + 31, |
||||
|
|
||||
|
VertexBuffers, |
||||
|
VertexBuffer0, |
||||
|
VertexBuffer31 = VertexBuffer0 + 31, |
||||
|
|
||||
|
VertexInstances, |
||||
|
VertexInstance0, |
||||
|
VertexInstance31 = VertexInstance0 + 31, |
||||
|
|
||||
|
ViewportTransform, |
||||
|
Viewports, |
||||
|
Viewport0, |
||||
|
Viewport15 = Viewport0 + 15, |
||||
|
|
||||
|
Scissors, |
||||
|
Scissor0, |
||||
|
Scissor15 = Scissor0 + 15, |
||||
|
|
||||
|
ColorMaskCommon, |
||||
|
ColorMasks, |
||||
|
ColorMask0, |
||||
|
ColorMask7 = ColorMask0 + 7, |
||||
|
|
||||
|
BlendColor, |
||||
|
BlendIndependentEnabled, |
||||
|
BlendStates, |
||||
|
BlendState0, |
||||
|
BlendState7 = BlendState0 + 7, |
||||
|
|
||||
|
Shaders, |
||||
|
ClipDistances, |
||||
|
|
||||
|
ColorMask, |
||||
|
FrontFace, |
||||
|
CullTest, |
||||
|
DepthMask, |
||||
|
DepthTest, |
||||
|
StencilTest, |
||||
|
AlphaTest, |
||||
|
PrimitiveRestart, |
||||
|
PolygonOffset, |
||||
|
MultisampleControl, |
||||
|
RasterizeEnable, |
||||
|
FramebufferSRGB, |
||||
|
LogicOp, |
||||
|
FragmentClampColor, |
||||
|
PointSize, |
||||
|
ClipControl, |
||||
|
DepthClampEnabled, |
||||
|
|
||||
|
Last |
||||
|
}; |
||||
|
static_assert(Last <= std::numeric_limits<u8>::max()); |
||||
|
|
||||
|
} // namespace Dirty |
||||
|
|
||||
|
class StateTracker { |
||||
|
public: |
||||
|
explicit StateTracker(Core::System& system); |
||||
|
|
||||
|
void Initialize(); |
||||
|
|
||||
|
void BindIndexBuffer(GLuint new_index_buffer) { |
||||
|
if (index_buffer == new_index_buffer) { |
||||
|
return; |
||||
|
} |
||||
|
index_buffer = new_index_buffer; |
||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, new_index_buffer); |
||||
|
} |
||||
|
|
||||
|
void NotifyScreenDrawVertexArray() { |
||||
|
auto& flags = system.GPU().Maxwell3D().dirty.flags; |
||||
|
flags[OpenGL::Dirty::VertexFormats] = true; |
||||
|
flags[OpenGL::Dirty::VertexFormat0 + 0] = true; |
||||
|
flags[OpenGL::Dirty::VertexFormat0 + 1] = true; |
||||
|
|
||||
|
flags[OpenGL::Dirty::VertexBuffers] = true; |
||||
|
flags[OpenGL::Dirty::VertexBuffer0] = true; |
||||
|
|
||||
|
flags[OpenGL::Dirty::VertexInstances] = true; |
||||
|
flags[OpenGL::Dirty::VertexInstance0 + 0] = true; |
||||
|
flags[OpenGL::Dirty::VertexInstance0 + 1] = true; |
||||
|
} |
||||
|
|
||||
|
void NotifyViewport0() { |
||||
|
auto& flags = system.GPU().Maxwell3D().dirty.flags; |
||||
|
flags[OpenGL::Dirty::Viewports] = true; |
||||
|
flags[OpenGL::Dirty::Viewport0] = true; |
||||
|
} |
||||
|
|
||||
|
void NotifyScissor0() { |
||||
|
auto& flags = system.GPU().Maxwell3D().dirty.flags; |
||||
|
flags[OpenGL::Dirty::Scissors] = true; |
||||
|
flags[OpenGL::Dirty::Scissor0] = true; |
||||
|
} |
||||
|
|
||||
|
void NotifyColorMask0() { |
||||
|
auto& flags = system.GPU().Maxwell3D().dirty.flags; |
||||
|
flags[OpenGL::Dirty::ColorMasks] = true; |
||||
|
flags[OpenGL::Dirty::ColorMask0] = true; |
||||
|
} |
||||
|
|
||||
|
void NotifyBlend0() { |
||||
|
auto& flags = system.GPU().Maxwell3D().dirty.flags; |
||||
|
flags[OpenGL::Dirty::BlendStates] = true; |
||||
|
flags[OpenGL::Dirty::BlendState0] = true; |
||||
|
} |
||||
|
|
||||
|
void NotifyFramebuffer() { |
||||
|
auto& flags = system.GPU().Maxwell3D().dirty.flags; |
||||
|
flags[VideoCommon::Dirty::RenderTargets] = true; |
||||
|
} |
||||
|
|
||||
|
void NotifyFrontFace() { |
||||
|
auto& flags = system.GPU().Maxwell3D().dirty.flags; |
||||
|
flags[OpenGL::Dirty::FrontFace] = true; |
||||
|
} |
||||
|
|
||||
|
void NotifyCullTest() { |
||||
|
auto& flags = system.GPU().Maxwell3D().dirty.flags; |
||||
|
flags[OpenGL::Dirty::CullTest] = true; |
||||
|
} |
||||
|
|
||||
|
void NotifyDepthMask() { |
||||
|
auto& flags = system.GPU().Maxwell3D().dirty.flags; |
||||
|
flags[OpenGL::Dirty::DepthMask] = true; |
||||
|
} |
||||
|
|
||||
|
void NotifyDepthTest() { |
||||
|
auto& flags = system.GPU().Maxwell3D().dirty.flags; |
||||
|
flags[OpenGL::Dirty::DepthTest] = true; |
||||
|
} |
||||
|
|
||||
|
void NotifyStencilTest() { |
||||
|
auto& flags = system.GPU().Maxwell3D().dirty.flags; |
||||
|
flags[OpenGL::Dirty::StencilTest] = true; |
||||
|
} |
||||
|
|
||||
|
void NotifyPolygonOffset() { |
||||
|
auto& flags = system.GPU().Maxwell3D().dirty.flags; |
||||
|
flags[OpenGL::Dirty::PolygonOffset] = true; |
||||
|
} |
||||
|
|
||||
|
void NotifyRasterizeEnable() { |
||||
|
auto& flags = system.GPU().Maxwell3D().dirty.flags; |
||||
|
flags[OpenGL::Dirty::RasterizeEnable] = true; |
||||
|
} |
||||
|
|
||||
|
void NotifyFramebufferSRGB() { |
||||
|
auto& flags = system.GPU().Maxwell3D().dirty.flags; |
||||
|
flags[OpenGL::Dirty::FramebufferSRGB] = true; |
||||
|
} |
||||
|
|
||||
|
void NotifyLogicOp() { |
||||
|
auto& flags = system.GPU().Maxwell3D().dirty.flags; |
||||
|
flags[OpenGL::Dirty::LogicOp] = true; |
||||
|
} |
||||
|
|
||||
|
void NotifyClipControl() { |
||||
|
auto& flags = system.GPU().Maxwell3D().dirty.flags; |
||||
|
flags[OpenGL::Dirty::ClipControl] = true; |
||||
|
} |
||||
|
|
||||
|
void NotifyAlphaTest() { |
||||
|
auto& flags = system.GPU().Maxwell3D().dirty.flags; |
||||
|
flags[OpenGL::Dirty::AlphaTest] = true; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
Core::System& system; |
||||
|
|
||||
|
GLuint index_buffer = 0; |
||||
|
}; |
||||
|
|
||||
|
} // namespace OpenGL |
||||
@ -0,0 +1,101 @@ |
|||||
|
// Copyright 2020 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include <algorithm>
|
||||
|
#include <cstddef>
|
||||
|
#include <iterator>
|
||||
|
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "core/core.h"
|
||||
|
#include "video_core/dirty_flags.h"
|
||||
|
#include "video_core/engines/maxwell_3d.h"
|
||||
|
#include "video_core/gpu.h"
|
||||
|
#include "video_core/renderer_vulkan/vk_state_tracker.h"
|
||||
|
|
||||
|
#define OFF(field_name) MAXWELL3D_REG_INDEX(field_name)
|
||||
|
#define NUM(field_name) (sizeof(Maxwell3D::Regs::field_name) / sizeof(u32))
|
||||
|
|
||||
|
namespace Vulkan { |
||||
|
|
||||
|
namespace { |
||||
|
|
||||
|
using namespace Dirty; |
||||
|
using namespace VideoCommon::Dirty; |
||||
|
using Tegra::Engines::Maxwell3D; |
||||
|
using Regs = Maxwell3D::Regs; |
||||
|
using Tables = Maxwell3D::DirtyState::Tables; |
||||
|
using Table = Maxwell3D::DirtyState::Table; |
||||
|
using Flags = Maxwell3D::DirtyState::Flags; |
||||
|
|
||||
|
Flags MakeInvalidationFlags() { |
||||
|
Flags flags{}; |
||||
|
flags[Viewports] = true; |
||||
|
flags[Scissors] = true; |
||||
|
flags[DepthBias] = true; |
||||
|
flags[BlendConstants] = true; |
||||
|
flags[DepthBounds] = true; |
||||
|
flags[StencilProperties] = true; |
||||
|
return flags; |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyViewports(Tables& tables) { |
||||
|
FillBlock(tables[0], OFF(viewport_transform), NUM(viewport_transform), Viewports); |
||||
|
FillBlock(tables[0], OFF(viewports), NUM(viewports), Viewports); |
||||
|
tables[0][OFF(viewport_transform_enabled)] = Viewports; |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyScissors(Tables& tables) { |
||||
|
FillBlock(tables[0], OFF(scissor_test), NUM(scissor_test), Scissors); |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyDepthBias(Tables& tables) { |
||||
|
auto& table = tables[0]; |
||||
|
table[OFF(polygon_offset_units)] = DepthBias; |
||||
|
table[OFF(polygon_offset_clamp)] = DepthBias; |
||||
|
table[OFF(polygon_offset_factor)] = DepthBias; |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyBlendConstants(Tables& tables) { |
||||
|
FillBlock(tables[0], OFF(blend_color), NUM(blend_color), BlendConstants); |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyDepthBounds(Tables& tables) { |
||||
|
FillBlock(tables[0], OFF(depth_bounds), NUM(depth_bounds), DepthBounds); |
||||
|
} |
||||
|
|
||||
|
void SetupDirtyStencilProperties(Tables& tables) { |
||||
|
auto& table = tables[0]; |
||||
|
table[OFF(stencil_two_side_enable)] = StencilProperties; |
||||
|
table[OFF(stencil_front_func_ref)] = StencilProperties; |
||||
|
table[OFF(stencil_front_mask)] = StencilProperties; |
||||
|
table[OFF(stencil_front_func_mask)] = StencilProperties; |
||||
|
table[OFF(stencil_back_func_ref)] = StencilProperties; |
||||
|
table[OFF(stencil_back_mask)] = StencilProperties; |
||||
|
table[OFF(stencil_back_func_mask)] = StencilProperties; |
||||
|
} |
||||
|
|
||||
|
} // Anonymous namespace
|
||||
|
|
||||
|
StateTracker::StateTracker(Core::System& system) |
||||
|
: system{system}, invalidation_flags{MakeInvalidationFlags()} {} |
||||
|
|
||||
|
void StateTracker::Initialize() { |
||||
|
auto& dirty = system.GPU().Maxwell3D().dirty; |
||||
|
auto& tables = dirty.tables; |
||||
|
SetupDirtyRenderTargets(tables); |
||||
|
SetupDirtyViewports(tables); |
||||
|
SetupDirtyScissors(tables); |
||||
|
SetupDirtyDepthBias(tables); |
||||
|
SetupDirtyBlendConstants(tables); |
||||
|
SetupDirtyDepthBounds(tables); |
||||
|
SetupDirtyStencilProperties(tables); |
||||
|
|
||||
|
SetupCommonOnWriteStores(dirty.on_write_stores); |
||||
|
} |
||||
|
|
||||
|
void StateTracker::InvalidateCommandBufferState() { |
||||
|
system.GPU().Maxwell3D().dirty.flags |= invalidation_flags; |
||||
|
} |
||||
|
|
||||
|
} // namespace Vulkan
|
||||
@ -0,0 +1,79 @@ |
|||||
|
// Copyright 2020 yuzu Emulator Project |
||||
|
// Licensed under GPLv2 or any later version |
||||
|
// Refer to the license.txt file included. |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <cstddef> |
||||
|
#include <limits> |
||||
|
|
||||
|
#include "common/common_types.h" |
||||
|
#include "core/core.h" |
||||
|
#include "video_core/dirty_flags.h" |
||||
|
#include "video_core/engines/maxwell_3d.h" |
||||
|
|
||||
|
namespace Vulkan { |
||||
|
|
||||
|
namespace Dirty { |
||||
|
|
||||
|
enum : u8 { |
||||
|
First = VideoCommon::Dirty::LastCommonEntry, |
||||
|
|
||||
|
Viewports, |
||||
|
Scissors, |
||||
|
DepthBias, |
||||
|
BlendConstants, |
||||
|
DepthBounds, |
||||
|
StencilProperties, |
||||
|
|
||||
|
Last |
||||
|
}; |
||||
|
static_assert(Last <= std::numeric_limits<u8>::max()); |
||||
|
|
||||
|
} // namespace Dirty |
||||
|
|
||||
|
class StateTracker { |
||||
|
public: |
||||
|
explicit StateTracker(Core::System& system); |
||||
|
|
||||
|
void Initialize(); |
||||
|
|
||||
|
void InvalidateCommandBufferState(); |
||||
|
|
||||
|
bool TouchViewports() { |
||||
|
return Exchange(Dirty::Viewports, false); |
||||
|
} |
||||
|
|
||||
|
bool TouchScissors() { |
||||
|
return Exchange(Dirty::Scissors, false); |
||||
|
} |
||||
|
|
||||
|
bool TouchDepthBias() { |
||||
|
return Exchange(Dirty::DepthBias, false); |
||||
|
} |
||||
|
|
||||
|
bool TouchBlendConstants() { |
||||
|
return Exchange(Dirty::BlendConstants, false); |
||||
|
} |
||||
|
|
||||
|
bool TouchDepthBounds() { |
||||
|
return Exchange(Dirty::DepthBounds, false); |
||||
|
} |
||||
|
|
||||
|
bool TouchStencilProperties() { |
||||
|
return Exchange(Dirty::StencilProperties, false); |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
bool Exchange(std::size_t id, bool new_value) const noexcept { |
||||
|
auto& flags = system.GPU().Maxwell3D().dirty.flags; |
||||
|
const bool is_dirty = flags[id]; |
||||
|
flags[id] = new_value; |
||||
|
return is_dirty; |
||||
|
} |
||||
|
|
||||
|
Core::System& system; |
||||
|
Tegra::Engines::Maxwell3D::DirtyState::Flags invalidation_flags; |
||||
|
}; |
||||
|
|
||||
|
} // namespace Vulkan |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue