glasm: Set transform feedback state
This commit is contained in:
parent
69b910e9e7
commit
6bc54e12a0
|
@ -12,7 +12,7 @@
|
||||||
#include "video_core/texture_cache/texture_cache.h"
|
#include "video_core/texture_cache/texture_cache.h"
|
||||||
|
|
||||||
namespace OpenGL {
|
namespace OpenGL {
|
||||||
|
namespace {
|
||||||
using Shader::ImageBufferDescriptor;
|
using Shader::ImageBufferDescriptor;
|
||||||
using Tegra::Texture::TexturePair;
|
using Tegra::Texture::TexturePair;
|
||||||
using VideoCommon::ImageId;
|
using VideoCommon::ImageId;
|
||||||
|
@ -20,6 +20,35 @@ using VideoCommon::ImageId;
|
||||||
constexpr u32 MAX_TEXTURES = 64;
|
constexpr u32 MAX_TEXTURES = 64;
|
||||||
constexpr u32 MAX_IMAGES = 8;
|
constexpr u32 MAX_IMAGES = 8;
|
||||||
|
|
||||||
|
/// Translates hardware transform feedback indices
|
||||||
|
/// @param location Hardware location
|
||||||
|
/// @return Pair of ARB_transform_feedback3 token stream first and third arguments
|
||||||
|
/// @note Read https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_transform_feedback3.txt
|
||||||
|
std::pair<GLint, GLint> TransformFeedbackEnum(u8 location) {
|
||||||
|
const u8 index = location / 4;
|
||||||
|
if (index >= 8 && index <= 39) {
|
||||||
|
return {GL_GENERIC_ATTRIB_NV, index - 8};
|
||||||
|
}
|
||||||
|
if (index >= 48 && index <= 55) {
|
||||||
|
return {GL_TEXTURE_COORD_NV, index - 48};
|
||||||
|
}
|
||||||
|
switch (index) {
|
||||||
|
case 7:
|
||||||
|
return {GL_POSITION, 0};
|
||||||
|
case 40:
|
||||||
|
return {GL_PRIMARY_COLOR_NV, 0};
|
||||||
|
case 41:
|
||||||
|
return {GL_SECONDARY_COLOR_NV, 0};
|
||||||
|
case 42:
|
||||||
|
return {GL_BACK_PRIMARY_COLOR_NV, 0};
|
||||||
|
case 43:
|
||||||
|
return {GL_BACK_SECONDARY_COLOR_NV, 0};
|
||||||
|
}
|
||||||
|
UNIMPLEMENTED_MSG("index={}", index);
|
||||||
|
return {GL_POSITION, 0};
|
||||||
|
}
|
||||||
|
} // Anonymous namespace
|
||||||
|
|
||||||
size_t GraphicsProgramKey::Hash() const noexcept {
|
size_t GraphicsProgramKey::Hash() const noexcept {
|
||||||
return static_cast<size_t>(Common::CityHash64(reinterpret_cast<const char*>(this), Size()));
|
return static_cast<size_t>(Common::CityHash64(reinterpret_cast<const char*>(this), Size()));
|
||||||
}
|
}
|
||||||
|
@ -34,7 +63,8 @@ GraphicsProgram::GraphicsProgram(TextureCache& texture_cache_, BufferCache& buff
|
||||||
ProgramManager& program_manager_, StateTracker& state_tracker_,
|
ProgramManager& program_manager_, StateTracker& state_tracker_,
|
||||||
OGLProgram program_,
|
OGLProgram program_,
|
||||||
std::array<OGLAssemblyProgram, 5> assembly_programs_,
|
std::array<OGLAssemblyProgram, 5> assembly_programs_,
|
||||||
const std::array<const Shader::Info*, 5>& infos)
|
const std::array<const Shader::Info*, 5>& infos,
|
||||||
|
const VideoCommon::TransformFeedbackState* xfb_state)
|
||||||
: texture_cache{texture_cache_}, buffer_cache{buffer_cache_},
|
: texture_cache{texture_cache_}, buffer_cache{buffer_cache_},
|
||||||
gpu_memory{gpu_memory_}, maxwell3d{maxwell3d_}, program_manager{program_manager_},
|
gpu_memory{gpu_memory_}, maxwell3d{maxwell3d_}, program_manager{program_manager_},
|
||||||
state_tracker{state_tracker_}, program{std::move(program_)}, assembly_programs{std::move(
|
state_tracker{state_tracker_}, program{std::move(program_)}, assembly_programs{std::move(
|
||||||
|
@ -74,6 +104,10 @@ GraphicsProgram::GraphicsProgram(TextureCache& texture_cache_, BufferCache& buff
|
||||||
}
|
}
|
||||||
ASSERT(num_textures <= MAX_TEXTURES);
|
ASSERT(num_textures <= MAX_TEXTURES);
|
||||||
ASSERT(num_images <= MAX_IMAGES);
|
ASSERT(num_images <= MAX_IMAGES);
|
||||||
|
|
||||||
|
if (assembly_programs[0].handle != 0 && xfb_state) {
|
||||||
|
GenerateTransformFeedbackState(*xfb_state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Spec {
|
struct Spec {
|
||||||
|
@ -302,4 +336,56 @@ void GraphicsProgram::Configure(bool is_indexed) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GraphicsProgram::GenerateTransformFeedbackState(
|
||||||
|
const VideoCommon::TransformFeedbackState& xfb_state) {
|
||||||
|
// TODO(Rodrigo): Inject SKIP_COMPONENTS*_NV when required. An unimplemented message will signal
|
||||||
|
// when this is required.
|
||||||
|
const auto& regs{maxwell3d.regs};
|
||||||
|
|
||||||
|
GLint* cursor{xfb_attribs.data()};
|
||||||
|
GLint* current_stream{xfb_streams.data()};
|
||||||
|
|
||||||
|
for (size_t feedback = 0; feedback < Maxwell::NumTransformFeedbackBuffers; ++feedback) {
|
||||||
|
const auto& layout = regs.tfb_layouts[feedback];
|
||||||
|
UNIMPLEMENTED_IF_MSG(layout.stride != layout.varying_count * 4, "Stride padding");
|
||||||
|
if (layout.varying_count == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
*current_stream = static_cast<GLint>(feedback);
|
||||||
|
if (current_stream != xfb_streams.data()) {
|
||||||
|
// When stepping one stream, push the expected token
|
||||||
|
cursor[0] = GL_NEXT_BUFFER_NV;
|
||||||
|
cursor[1] = 0;
|
||||||
|
cursor[2] = 0;
|
||||||
|
cursor += XFB_ENTRY_STRIDE;
|
||||||
|
}
|
||||||
|
++current_stream;
|
||||||
|
|
||||||
|
const auto& locations = regs.tfb_varying_locs[feedback];
|
||||||
|
std::optional<u8> current_index;
|
||||||
|
for (u32 offset = 0; offset < layout.varying_count; ++offset) {
|
||||||
|
const u8 location = locations[offset];
|
||||||
|
const u8 index = location / 4;
|
||||||
|
|
||||||
|
if (current_index == index) {
|
||||||
|
// Increase number of components of the previous attachment
|
||||||
|
++cursor[-2];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
current_index = index;
|
||||||
|
|
||||||
|
std::tie(cursor[0], cursor[2]) = TransformFeedbackEnum(location);
|
||||||
|
cursor[1] = 1;
|
||||||
|
cursor += XFB_ENTRY_STRIDE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
num_xfb_attribs = static_cast<GLsizei>((cursor - xfb_attribs.data()) / XFB_ENTRY_STRIDE);
|
||||||
|
num_xfb_strides = static_cast<GLsizei>(current_stream - xfb_streams.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphicsProgram::ConfigureTransformFeedbackImpl() const {
|
||||||
|
glTransformFeedbackStreamAttribsNV(num_xfb_attribs, xfb_attribs.data(), num_xfb_strides,
|
||||||
|
xfb_streams.data(), GL_INTERLEAVED_ATTRIBS);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace OpenGL
|
} // namespace OpenGL
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "video_core/renderer_opengl/gl_buffer_cache.h"
|
#include "video_core/renderer_opengl/gl_buffer_cache.h"
|
||||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||||
#include "video_core/renderer_opengl/gl_texture_cache.h"
|
#include "video_core/renderer_opengl/gl_texture_cache.h"
|
||||||
|
#include "video_core/transform_feedback.h"
|
||||||
|
|
||||||
namespace OpenGL {
|
namespace OpenGL {
|
||||||
|
|
||||||
|
@ -24,16 +25,6 @@ class ProgramManager;
|
||||||
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
||||||
|
|
||||||
struct GraphicsProgramKey {
|
struct GraphicsProgramKey {
|
||||||
struct TransformFeedbackState {
|
|
||||||
struct Layout {
|
|
||||||
u32 stream;
|
|
||||||
u32 varying_count;
|
|
||||||
u32 stride;
|
|
||||||
};
|
|
||||||
std::array<Layout, Maxwell::NumTransformFeedbackBuffers> layouts;
|
|
||||||
std::array<std::array<u8, 128>, Maxwell::NumTransformFeedbackBuffers> varyings;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::array<u64, 6> unique_hashes;
|
std::array<u64, 6> unique_hashes;
|
||||||
union {
|
union {
|
||||||
u32 raw;
|
u32 raw;
|
||||||
|
@ -45,7 +36,7 @@ struct GraphicsProgramKey {
|
||||||
BitField<10, 1, u32> tessellation_clockwise;
|
BitField<10, 1, u32> tessellation_clockwise;
|
||||||
};
|
};
|
||||||
std::array<u32, 3> padding;
|
std::array<u32, 3> padding;
|
||||||
TransformFeedbackState xfb_state;
|
VideoCommon::TransformFeedbackState xfb_state;
|
||||||
|
|
||||||
size_t Hash() const noexcept;
|
size_t Hash() const noexcept;
|
||||||
|
|
||||||
|
@ -75,11 +66,22 @@ public:
|
||||||
ProgramManager& program_manager_, StateTracker& state_tracker_,
|
ProgramManager& program_manager_, StateTracker& state_tracker_,
|
||||||
OGLProgram program_,
|
OGLProgram program_,
|
||||||
std::array<OGLAssemblyProgram, 5> assembly_programs_,
|
std::array<OGLAssemblyProgram, 5> assembly_programs_,
|
||||||
const std::array<const Shader::Info*, 5>& infos);
|
const std::array<const Shader::Info*, 5>& infos,
|
||||||
|
const VideoCommon::TransformFeedbackState* xfb_state);
|
||||||
|
|
||||||
void Configure(bool is_indexed);
|
void Configure(bool is_indexed);
|
||||||
|
|
||||||
|
void ConfigureTransformFeedback() const {
|
||||||
|
if (num_xfb_attribs != 0) {
|
||||||
|
ConfigureTransformFeedbackImpl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void GenerateTransformFeedbackState(const VideoCommon::TransformFeedbackState& xfb_state);
|
||||||
|
|
||||||
|
void ConfigureTransformFeedbackImpl() const;
|
||||||
|
|
||||||
TextureCache& texture_cache;
|
TextureCache& texture_cache;
|
||||||
BufferCache& buffer_cache;
|
BufferCache& buffer_cache;
|
||||||
Tegra::MemoryManager& gpu_memory;
|
Tegra::MemoryManager& gpu_memory;
|
||||||
|
@ -96,6 +98,12 @@ private:
|
||||||
std::array<u32, 5> base_storage_bindings{};
|
std::array<u32, 5> base_storage_bindings{};
|
||||||
std::array<u32, 5> num_texture_buffers{};
|
std::array<u32, 5> num_texture_buffers{};
|
||||||
std::array<u32, 5> num_image_buffers{};
|
std::array<u32, 5> num_image_buffers{};
|
||||||
|
|
||||||
|
static constexpr std::size_t XFB_ENTRY_STRIDE = 3;
|
||||||
|
GLsizei num_xfb_attribs{};
|
||||||
|
GLsizei num_xfb_strides{};
|
||||||
|
std::array<GLint, 128 * XFB_ENTRY_STRIDE * Maxwell::NumTransformFeedbackBuffers> xfb_attribs{};
|
||||||
|
std::array<GLint, Maxwell::NumTransformFeedbackBuffers> xfb_streams{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace OpenGL
|
} // namespace OpenGL
|
||||||
|
|
|
@ -51,37 +51,8 @@ MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(128, 128, 192));
|
||||||
MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Management", MP_RGB(100, 255, 100));
|
MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Management", MP_RGB(100, 255, 100));
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr size_t NUM_SUPPORTED_VERTEX_ATTRIBUTES = 16;
|
constexpr size_t NUM_SUPPORTED_VERTEX_ATTRIBUTES = 16;
|
||||||
|
|
||||||
/// Translates hardware transform feedback indices
|
|
||||||
/// @param location Hardware location
|
|
||||||
/// @return Pair of ARB_transform_feedback3 token stream first and third arguments
|
|
||||||
/// @note Read https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_transform_feedback3.txt
|
|
||||||
std::pair<GLint, GLint> TransformFeedbackEnum(u8 location) {
|
|
||||||
const u8 index = location / 4;
|
|
||||||
if (index >= 8 && index <= 39) {
|
|
||||||
return {GL_GENERIC_ATTRIB_NV, index - 8};
|
|
||||||
}
|
|
||||||
if (index >= 48 && index <= 55) {
|
|
||||||
return {GL_TEXTURE_COORD_NV, index - 48};
|
|
||||||
}
|
|
||||||
switch (index) {
|
|
||||||
case 7:
|
|
||||||
return {GL_POSITION, 0};
|
|
||||||
case 40:
|
|
||||||
return {GL_PRIMARY_COLOR_NV, 0};
|
|
||||||
case 41:
|
|
||||||
return {GL_SECONDARY_COLOR_NV, 0};
|
|
||||||
case 42:
|
|
||||||
return {GL_BACK_PRIMARY_COLOR_NV, 0};
|
|
||||||
case 43:
|
|
||||||
return {GL_BACK_SECONDARY_COLOR_NV, 0};
|
|
||||||
}
|
|
||||||
UNIMPLEMENTED_MSG("index={}", index);
|
|
||||||
return {GL_POSITION, 0};
|
|
||||||
}
|
|
||||||
|
|
||||||
void oglEnable(GLenum cap, bool state) {
|
void oglEnable(GLenum cap, bool state) {
|
||||||
(state ? glEnable : glDisable)(cap);
|
(state ? glEnable : glDisable)(cap);
|
||||||
}
|
}
|
||||||
|
@ -253,7 +224,7 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
|
||||||
program->Configure(is_indexed);
|
program->Configure(is_indexed);
|
||||||
|
|
||||||
const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(maxwell3d.regs.draw.topology);
|
const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(maxwell3d.regs.draw.topology);
|
||||||
BeginTransformFeedback(primitive_mode);
|
BeginTransformFeedback(program, primitive_mode);
|
||||||
|
|
||||||
const GLuint base_instance = static_cast<GLuint>(maxwell3d.regs.vb_base_instance);
|
const GLuint base_instance = static_cast<GLuint>(maxwell3d.regs.vb_base_instance);
|
||||||
const GLsizei num_instances =
|
const GLsizei num_instances =
|
||||||
|
@ -1025,68 +996,13 @@ void RasterizerOpenGL::SyncFramebufferSRGB() {
|
||||||
oglEnable(GL_FRAMEBUFFER_SRGB, maxwell3d.regs.framebuffer_srgb);
|
oglEnable(GL_FRAMEBUFFER_SRGB, maxwell3d.regs.framebuffer_srgb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncTransformFeedback() {
|
void RasterizerOpenGL::BeginTransformFeedback(GraphicsProgram* program, GLenum primitive_mode) {
|
||||||
// TODO(Rodrigo): Inject SKIP_COMPONENTS*_NV when required. An unimplemented message will signal
|
|
||||||
// when this is required.
|
|
||||||
const auto& regs = maxwell3d.regs;
|
|
||||||
|
|
||||||
static constexpr std::size_t STRIDE = 3;
|
|
||||||
std::array<GLint, 128 * STRIDE * Maxwell::NumTransformFeedbackBuffers> attribs;
|
|
||||||
std::array<GLint, Maxwell::NumTransformFeedbackBuffers> streams;
|
|
||||||
|
|
||||||
GLint* cursor = attribs.data();
|
|
||||||
GLint* current_stream = streams.data();
|
|
||||||
|
|
||||||
for (std::size_t feedback = 0; feedback < Maxwell::NumTransformFeedbackBuffers; ++feedback) {
|
|
||||||
const auto& layout = regs.tfb_layouts[feedback];
|
|
||||||
UNIMPLEMENTED_IF_MSG(layout.stride != layout.varying_count * 4, "Stride padding");
|
|
||||||
if (layout.varying_count == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
*current_stream = static_cast<GLint>(feedback);
|
|
||||||
if (current_stream != streams.data()) {
|
|
||||||
// When stepping one stream, push the expected token
|
|
||||||
cursor[0] = GL_NEXT_BUFFER_NV;
|
|
||||||
cursor[1] = 0;
|
|
||||||
cursor[2] = 0;
|
|
||||||
cursor += STRIDE;
|
|
||||||
}
|
|
||||||
++current_stream;
|
|
||||||
|
|
||||||
const auto& locations = regs.tfb_varying_locs[feedback];
|
|
||||||
std::optional<u8> current_index;
|
|
||||||
for (u32 offset = 0; offset < layout.varying_count; ++offset) {
|
|
||||||
const u8 location = locations[offset];
|
|
||||||
const u8 index = location / 4;
|
|
||||||
|
|
||||||
if (current_index == index) {
|
|
||||||
// Increase number of components of the previous attachment
|
|
||||||
++cursor[-2];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
current_index = index;
|
|
||||||
|
|
||||||
std::tie(cursor[0], cursor[2]) = TransformFeedbackEnum(location);
|
|
||||||
cursor[1] = 1;
|
|
||||||
cursor += STRIDE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const GLsizei num_attribs = static_cast<GLsizei>((cursor - attribs.data()) / STRIDE);
|
|
||||||
const GLsizei num_strides = static_cast<GLsizei>(current_stream - streams.data());
|
|
||||||
glTransformFeedbackStreamAttribsNV(num_attribs, attribs.data(), num_strides, streams.data(),
|
|
||||||
GL_INTERLEAVED_ATTRIBS);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RasterizerOpenGL::BeginTransformFeedback(GLenum primitive_mode) {
|
|
||||||
const auto& regs = maxwell3d.regs;
|
const auto& regs = maxwell3d.regs;
|
||||||
if (regs.tfb_enabled == 0) {
|
if (regs.tfb_enabled == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (device.UseAssemblyShaders()) {
|
program->ConfigureTransformFeedback();
|
||||||
SyncTransformFeedback();
|
|
||||||
}
|
|
||||||
UNIMPLEMENTED_IF(regs.IsShaderConfigEnabled(Maxwell::ShaderProgram::TesselationControl) ||
|
UNIMPLEMENTED_IF(regs.IsShaderConfigEnabled(Maxwell::ShaderProgram::TesselationControl) ||
|
||||||
regs.IsShaderConfigEnabled(Maxwell::ShaderProgram::TesselationEval) ||
|
regs.IsShaderConfigEnabled(Maxwell::ShaderProgram::TesselationEval) ||
|
||||||
regs.IsShaderConfigEnabled(Maxwell::ShaderProgram::Geometry));
|
regs.IsShaderConfigEnabled(Maxwell::ShaderProgram::Geometry));
|
||||||
|
@ -1100,12 +1016,10 @@ void RasterizerOpenGL::BeginTransformFeedback(GLenum primitive_mode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::EndTransformFeedback() {
|
void RasterizerOpenGL::EndTransformFeedback() {
|
||||||
const auto& regs = maxwell3d.regs;
|
if (maxwell3d.regs.tfb_enabled != 0) {
|
||||||
if (regs.tfb_enabled == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
glEndTransformFeedback();
|
glEndTransformFeedback();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_) : buffer_cache{buffer_cache_} {}
|
AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_) : buffer_cache{buffer_cache_} {}
|
||||||
|
|
||||||
|
|
|
@ -193,12 +193,8 @@ private:
|
||||||
/// Syncs vertex instances to match the guest state
|
/// Syncs vertex instances to match the guest state
|
||||||
void SyncVertexInstances();
|
void SyncVertexInstances();
|
||||||
|
|
||||||
/// Syncs transform feedback state to match guest state
|
|
||||||
/// @note Only valid on assembly shaders
|
|
||||||
void SyncTransformFeedback();
|
|
||||||
|
|
||||||
/// Begin a transform feedback
|
/// Begin a transform feedback
|
||||||
void BeginTransformFeedback(GLenum primitive_mode);
|
void BeginTransformFeedback(GraphicsProgram* program, GLenum primitive_mode);
|
||||||
|
|
||||||
/// End a transform feedback
|
/// End a transform feedback
|
||||||
void EndTransformFeedback();
|
void EndTransformFeedback();
|
||||||
|
|
|
@ -254,6 +254,17 @@ Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsProgramKey& key,
|
||||||
}
|
}
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetXfbState(VideoCommon::TransformFeedbackState& state, const Maxwell& regs) {
|
||||||
|
std::ranges::transform(regs.tfb_layouts, state.layouts.begin(), [](const auto& layout) {
|
||||||
|
return VideoCommon::TransformFeedbackState::Layout{
|
||||||
|
.stream = layout.stream,
|
||||||
|
.varying_count = layout.varying_count,
|
||||||
|
.stride = layout.stride,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
state.varyings = regs.tfb_varying_locs;
|
||||||
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindow& emu_window_,
|
ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindow& emu_window_,
|
||||||
|
@ -282,7 +293,10 @@ GraphicsProgram* ShaderCache::CurrentGraphicsProgram() {
|
||||||
graphics_key.tessellation_primitive.Assign(regs.tess_mode.prim.Value());
|
graphics_key.tessellation_primitive.Assign(regs.tess_mode.prim.Value());
|
||||||
graphics_key.tessellation_spacing.Assign(regs.tess_mode.spacing.Value());
|
graphics_key.tessellation_spacing.Assign(regs.tess_mode.spacing.Value());
|
||||||
graphics_key.tessellation_clockwise.Assign(regs.tess_mode.cw.Value());
|
graphics_key.tessellation_clockwise.Assign(regs.tess_mode.cw.Value());
|
||||||
|
graphics_key.xfb_enabled.Assign(regs.tfb_enabled != 0 ? 1 : 0);
|
||||||
|
if (graphics_key.xfb_enabled) {
|
||||||
|
SetXfbState(graphics_key.xfb_state, regs);
|
||||||
|
}
|
||||||
const auto [pair, is_new]{graphics_cache.try_emplace(graphics_key)};
|
const auto [pair, is_new]{graphics_cache.try_emplace(graphics_key)};
|
||||||
auto& program{pair->second};
|
auto& program{pair->second};
|
||||||
if (is_new) {
|
if (is_new) {
|
||||||
|
@ -368,7 +382,8 @@ std::unique_ptr<GraphicsProgram> ShaderCache::CreateGraphicsProgram(
|
||||||
}
|
}
|
||||||
return std::make_unique<GraphicsProgram>(
|
return std::make_unique<GraphicsProgram>(
|
||||||
texture_cache, buffer_cache, gpu_memory, maxwell3d, program_manager, state_tracker,
|
texture_cache, buffer_cache, gpu_memory, maxwell3d, program_manager, state_tracker,
|
||||||
std::move(source_program), std::move(assembly_programs), infos);
|
std::move(source_program), std::move(assembly_programs), infos,
|
||||||
|
key.xfb_enabled != 0 ? &key.xfb_state : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<ComputeProgram> ShaderCache::CreateComputeProgram(
|
std::unique_ptr<ComputeProgram> ShaderCache::CreateComputeProgram(
|
||||||
|
|
Reference in New Issue