|
|
@ -297,11 +297,7 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
|
|
|
|
MICROPROFILE_SCOPE(OpenGL_Shader);
|
|
|
|
MICROPROFILE_SCOPE(OpenGL_Shader);
|
|
|
|
auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
|
|
|
|
auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
|
|
|
|
|
|
|
|
|
|
|
|
// Next available bindpoints to use when uploading the const buffers and textures to the GLSL
|
|
|
|
BaseBindings base_bindings;
|
|
|
|
// shaders. The constbuffer bindpoint starts after the shader stage configuration bind points.
|
|
|
|
|
|
|
|
u32 current_constbuffer_bindpoint = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage;
|
|
|
|
|
|
|
|
u32 current_gmem_bindpoint = 0;
|
|
|
|
|
|
|
|
u32 current_texture_bindpoint = 0;
|
|
|
|
|
|
|
|
std::array<bool, Maxwell::NumClipDistances> clip_distances{};
|
|
|
|
std::array<bool, Maxwell::NumClipDistances> clip_distances{};
|
|
|
|
|
|
|
|
|
|
|
|
for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
|
|
|
|
for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
|
|
|
@ -325,47 +321,35 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
|
|
|
|
const GLintptr offset = buffer_cache.UploadHostMemory(
|
|
|
|
const GLintptr offset = buffer_cache.UploadHostMemory(
|
|
|
|
&ubo, sizeof(ubo), static_cast<std::size_t>(uniform_buffer_alignment));
|
|
|
|
&ubo, sizeof(ubo), static_cast<std::size_t>(uniform_buffer_alignment));
|
|
|
|
|
|
|
|
|
|
|
|
// Bind the buffer
|
|
|
|
// Bind the emulation info buffer
|
|
|
|
glBindBufferRange(GL_UNIFORM_BUFFER, static_cast<GLuint>(stage), buffer_cache.GetHandle(),
|
|
|
|
glBindBufferRange(GL_UNIFORM_BUFFER, base_bindings.cbuf, buffer_cache.GetHandle(), offset,
|
|
|
|
offset, static_cast<GLsizeiptr>(sizeof(ubo)));
|
|
|
|
static_cast<GLsizeiptr>(sizeof(ubo)));
|
|
|
|
|
|
|
|
|
|
|
|
Shader shader{shader_cache.GetStageProgram(program)};
|
|
|
|
Shader shader{shader_cache.GetStageProgram(program)};
|
|
|
|
|
|
|
|
const auto [program_handle, next_bindings] =
|
|
|
|
|
|
|
|
shader->GetProgramHandle(primitive_mode, base_bindings);
|
|
|
|
|
|
|
|
|
|
|
|
switch (program) {
|
|
|
|
switch (program) {
|
|
|
|
case Maxwell::ShaderProgram::VertexA:
|
|
|
|
case Maxwell::ShaderProgram::VertexA:
|
|
|
|
case Maxwell::ShaderProgram::VertexB: {
|
|
|
|
case Maxwell::ShaderProgram::VertexB:
|
|
|
|
shader_program_manager->UseProgrammableVertexShader(
|
|
|
|
shader_program_manager->UseProgrammableVertexShader(program_handle);
|
|
|
|
shader->GetProgramHandle(primitive_mode));
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Maxwell::ShaderProgram::Geometry:
|
|
|
|
case Maxwell::ShaderProgram::Geometry: {
|
|
|
|
shader_program_manager->UseProgrammableGeometryShader(program_handle);
|
|
|
|
shader_program_manager->UseProgrammableGeometryShader(
|
|
|
|
|
|
|
|
shader->GetProgramHandle(primitive_mode));
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Maxwell::ShaderProgram::Fragment:
|
|
|
|
case Maxwell::ShaderProgram::Fragment: {
|
|
|
|
shader_program_manager->UseProgrammableFragmentShader(program_handle);
|
|
|
|
shader_program_manager->UseProgrammableFragmentShader(
|
|
|
|
|
|
|
|
shader->GetProgramHandle(primitive_mode));
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
LOG_CRITICAL(HW_GPU, "Unimplemented shader index={}, enable={}, offset=0x{:08X}", index,
|
|
|
|
LOG_CRITICAL(HW_GPU, "Unimplemented shader index={}, enable={}, offset=0x{:08X}", index,
|
|
|
|
shader_config.enable.Value(), shader_config.offset);
|
|
|
|
shader_config.enable.Value(), shader_config.offset);
|
|
|
|
UNREACHABLE();
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Configure the const buffers for this shader stage.
|
|
|
|
const auto stage_enum = static_cast<Maxwell::ShaderStage>(stage);
|
|
|
|
current_constbuffer_bindpoint =
|
|
|
|
SetupConstBuffers(stage_enum, shader, program_handle, base_bindings);
|
|
|
|
SetupConstBuffers(static_cast<Maxwell::ShaderStage>(stage), shader, primitive_mode,
|
|
|
|
SetupGlobalRegions(stage_enum, shader, program_handle, base_bindings);
|
|
|
|
current_constbuffer_bindpoint);
|
|
|
|
SetupTextures(stage_enum, shader, program_handle, base_bindings);
|
|
|
|
|
|
|
|
|
|
|
|
// Configure global memory regions for this shader stage.
|
|
|
|
|
|
|
|
current_gmem_bindpoint = SetupGlobalRegions(static_cast<Maxwell::ShaderStage>(stage),
|
|
|
|
|
|
|
|
shader, primitive_mode, current_gmem_bindpoint);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Configure the textures for this shader stage.
|
|
|
|
|
|
|
|
current_texture_bindpoint = SetupTextures(static_cast<Maxwell::ShaderStage>(stage), shader,
|
|
|
|
|
|
|
|
primitive_mode, current_texture_bindpoint);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Workaround for Intel drivers.
|
|
|
|
// Workaround for Intel drivers.
|
|
|
|
// When a clip distance is enabled but not set in the shader it crops parts of the screen
|
|
|
|
// When a clip distance is enabled but not set in the shader it crops parts of the screen
|
|
|
@ -380,6 +364,8 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
|
|
|
|
// VertexB was combined with VertexA, so we skip the VertexB iteration
|
|
|
|
// VertexB was combined with VertexA, so we skip the VertexB iteration
|
|
|
|
index++;
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
base_bindings = next_bindings;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SyncClipEnabled(clip_distances);
|
|
|
|
SyncClipEnabled(clip_distances);
|
|
|
@ -929,8 +915,9 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shader,
|
|
|
|
void RasterizerOpenGL::SetupConstBuffers(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage,
|
|
|
|
GLenum primitive_mode, u32 current_bindpoint) {
|
|
|
|
const Shader& shader, GLuint program_handle,
|
|
|
|
|
|
|
|
BaseBindings base_bindings) {
|
|
|
|
MICROPROFILE_SCOPE(OpenGL_UBO);
|
|
|
|
MICROPROFILE_SCOPE(OpenGL_UBO);
|
|
|
|
const auto& gpu = Core::System::GetInstance().GPU();
|
|
|
|
const auto& gpu = Core::System::GetInstance().GPU();
|
|
|
|
const auto& maxwell3d = gpu.Maxwell3D();
|
|
|
|
const auto& maxwell3d = gpu.Maxwell3D();
|
|
|
@ -978,92 +965,73 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shad
|
|
|
|
size = Common::AlignUp(size, sizeof(GLvec4));
|
|
|
|
size = Common::AlignUp(size, sizeof(GLvec4));
|
|
|
|
ASSERT_MSG(size <= MaxConstbufferSize, "Constbuffer too big");
|
|
|
|
ASSERT_MSG(size <= MaxConstbufferSize, "Constbuffer too big");
|
|
|
|
|
|
|
|
|
|
|
|
GLintptr const_buffer_offset = buffer_cache.UploadMemory(
|
|
|
|
const GLintptr const_buffer_offset = buffer_cache.UploadMemory(
|
|
|
|
buffer.address, size, static_cast<std::size_t>(uniform_buffer_alignment));
|
|
|
|
buffer.address, size, static_cast<std::size_t>(uniform_buffer_alignment));
|
|
|
|
|
|
|
|
|
|
|
|
// Now configure the bindpoint of the buffer inside the shader
|
|
|
|
|
|
|
|
glUniformBlockBinding(shader->GetProgramHandle(primitive_mode),
|
|
|
|
|
|
|
|
shader->GetProgramResourceIndex(used_buffer),
|
|
|
|
|
|
|
|
current_bindpoint + bindpoint);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Prepare values for multibind
|
|
|
|
// Prepare values for multibind
|
|
|
|
bind_buffers[bindpoint] = buffer_cache.GetHandle();
|
|
|
|
bind_buffers[bindpoint] = buffer_cache.GetHandle();
|
|
|
|
bind_offsets[bindpoint] = const_buffer_offset;
|
|
|
|
bind_offsets[bindpoint] = const_buffer_offset;
|
|
|
|
bind_sizes[bindpoint] = size;
|
|
|
|
bind_sizes[bindpoint] = size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
glBindBuffersRange(GL_UNIFORM_BUFFER, current_bindpoint, static_cast<GLsizei>(entries.size()),
|
|
|
|
// The first binding is reserved for emulation values
|
|
|
|
|
|
|
|
const GLuint ubo_base_binding = base_bindings.cbuf + 1;
|
|
|
|
|
|
|
|
glBindBuffersRange(GL_UNIFORM_BUFFER, ubo_base_binding, static_cast<GLsizei>(entries.size()),
|
|
|
|
bind_buffers.data(), bind_offsets.data(), bind_sizes.data());
|
|
|
|
bind_buffers.data(), bind_offsets.data(), bind_sizes.data());
|
|
|
|
|
|
|
|
|
|
|
|
return current_bindpoint + static_cast<u32>(entries.size());
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
u32 RasterizerOpenGL::SetupGlobalRegions(Maxwell::ShaderStage stage, Shader& shader,
|
|
|
|
void RasterizerOpenGL::SetupGlobalRegions(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage,
|
|
|
|
GLenum primitive_mode, u32 current_bindpoint) {
|
|
|
|
const Shader& shader, GLenum primitive_mode,
|
|
|
|
for (const auto& global_region : shader->GetShaderEntries().global_memory_entries) {
|
|
|
|
BaseBindings base_bindings) {
|
|
|
|
const auto& region =
|
|
|
|
// TODO(Rodrigo): Use ARB_multi_bind here
|
|
|
|
global_cache.GetGlobalRegion(global_region, static_cast<Maxwell::ShaderStage>(stage));
|
|
|
|
const auto& entries = shader->GetShaderEntries().global_memory_entries;
|
|
|
|
const GLuint block_index{shader->GetProgramResourceIndex(global_region)};
|
|
|
|
|
|
|
|
ASSERT(block_index != GL_INVALID_INDEX);
|
|
|
|
for (u32 bindpoint = 0; bindpoint < static_cast<u32>(entries.size()); ++bindpoint) {
|
|
|
|
|
|
|
|
const auto& entry = entries[bindpoint];
|
|
|
|
|
|
|
|
const u32 current_bindpoint = base_bindings.gmem + bindpoint;
|
|
|
|
|
|
|
|
const auto& region = global_cache.GetGlobalRegion(entry, stage);
|
|
|
|
|
|
|
|
|
|
|
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, current_bindpoint, region->GetBufferHandle());
|
|
|
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, current_bindpoint, region->GetBufferHandle());
|
|
|
|
glShaderStorageBlockBinding(shader->GetProgramHandle(primitive_mode), block_index,
|
|
|
|
|
|
|
|
current_bindpoint);
|
|
|
|
|
|
|
|
++current_bindpoint;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return current_bindpoint;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
|
|
|
|
void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& shader,
|
|
|
|
GLenum primitive_mode, u32 current_unit) {
|
|
|
|
GLuint program_handle, BaseBindings base_bindings) {
|
|
|
|
MICROPROFILE_SCOPE(OpenGL_Texture);
|
|
|
|
MICROPROFILE_SCOPE(OpenGL_Texture);
|
|
|
|
const auto& gpu = Core::System::GetInstance().GPU();
|
|
|
|
const auto& gpu = Core::System::GetInstance().GPU();
|
|
|
|
const auto& maxwell3d = gpu.Maxwell3D();
|
|
|
|
const auto& maxwell3d = gpu.Maxwell3D();
|
|
|
|
const auto& entries = shader->GetShaderEntries().samplers;
|
|
|
|
const auto& entries = shader->GetShaderEntries().samplers;
|
|
|
|
|
|
|
|
|
|
|
|
ASSERT_MSG(current_unit + entries.size() <= std::size(state.texture_units),
|
|
|
|
ASSERT_MSG(base_bindings.sampler + entries.size() <= std::size(state.texture_units),
|
|
|
|
"Exceeded the number of active textures.");
|
|
|
|
"Exceeded the number of active textures.");
|
|
|
|
|
|
|
|
|
|
|
|
for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
|
|
|
|
for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
|
|
|
|
const auto& entry = entries[bindpoint];
|
|
|
|
const auto& entry = entries[bindpoint];
|
|
|
|
const u32 current_bindpoint = current_unit + bindpoint;
|
|
|
|
const u32 current_bindpoint = base_bindings.sampler + bindpoint;
|
|
|
|
|
|
|
|
auto& unit = state.texture_units[current_bindpoint];
|
|
|
|
// Bind the uniform to the sampler.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
glProgramUniform1i(shader->GetProgramHandle(primitive_mode),
|
|
|
|
|
|
|
|
shader->GetUniformLocation(entry), current_bindpoint);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const auto texture = maxwell3d.GetStageTexture(entry.GetStage(), entry.GetOffset());
|
|
|
|
const auto texture = maxwell3d.GetStageTexture(entry.GetStage(), entry.GetOffset());
|
|
|
|
|
|
|
|
|
|
|
|
if (!texture.enabled) {
|
|
|
|
if (!texture.enabled) {
|
|
|
|
state.texture_units[current_bindpoint].texture = 0;
|
|
|
|
unit.texture = 0;
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc);
|
|
|
|
texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc);
|
|
|
|
|
|
|
|
|
|
|
|
Surface surface = res_cache.GetTextureSurface(texture, entry);
|
|
|
|
Surface surface = res_cache.GetTextureSurface(texture, entry);
|
|
|
|
if (surface != nullptr) {
|
|
|
|
if (surface != nullptr) {
|
|
|
|
const GLuint handle =
|
|
|
|
unit.texture =
|
|
|
|
entry.IsArray() ? surface->TextureLayer().handle : surface->Texture().handle;
|
|
|
|
entry.IsArray() ? surface->TextureLayer().handle : surface->Texture().handle;
|
|
|
|
const GLenum target = entry.IsArray() ? surface->TargetLayer() : surface->Target();
|
|
|
|
unit.target = entry.IsArray() ? surface->TargetLayer() : surface->Target();
|
|
|
|
state.texture_units[current_bindpoint].texture = handle;
|
|
|
|
unit.swizzle.r = MaxwellToGL::SwizzleSource(texture.tic.x_source);
|
|
|
|
state.texture_units[current_bindpoint].target = target;
|
|
|
|
unit.swizzle.g = MaxwellToGL::SwizzleSource(texture.tic.y_source);
|
|
|
|
state.texture_units[current_bindpoint].swizzle.r =
|
|
|
|
unit.swizzle.b = MaxwellToGL::SwizzleSource(texture.tic.z_source);
|
|
|
|
MaxwellToGL::SwizzleSource(texture.tic.x_source);
|
|
|
|
unit.swizzle.a = MaxwellToGL::SwizzleSource(texture.tic.w_source);
|
|
|
|
state.texture_units[current_bindpoint].swizzle.g =
|
|
|
|
|
|
|
|
MaxwellToGL::SwizzleSource(texture.tic.y_source);
|
|
|
|
|
|
|
|
state.texture_units[current_bindpoint].swizzle.b =
|
|
|
|
|
|
|
|
MaxwellToGL::SwizzleSource(texture.tic.z_source);
|
|
|
|
|
|
|
|
state.texture_units[current_bindpoint].swizzle.a =
|
|
|
|
|
|
|
|
MaxwellToGL::SwizzleSource(texture.tic.w_source);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// Can occur when texture addr is null or its memory is unmapped/invalid
|
|
|
|
// Can occur when texture addr is null or its memory is unmapped/invalid
|
|
|
|
state.texture_units[current_bindpoint].texture = 0;
|
|
|
|
unit.texture = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return current_unit + static_cast<u32>(entries.size());
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
|
|
|
|
void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
|
|
|
|