diff options
| author | 2018-06-06 12:58:16 -0500 | |
|---|---|---|
| committer | 2018-06-06 12:58:16 -0500 | |
| commit | dbfc39d21492dd1346b0e0d7ab5a2dbd989432bd (patch) | |
| tree | fa95ce57c5f16a01b766efe2b49ed90888800e3d | |
| parent | nvdrv/devices/nvidia_ctrl_gpu : add IoctlCommands with their params (#524) (diff) | |
| download | yuzu-dbfc39d21492dd1346b0e0d7ab5a2dbd989432bd.tar.gz yuzu-dbfc39d21492dd1346b0e0d7ab5a2dbd989432bd.tar.xz yuzu-dbfc39d21492dd1346b0e0d7ab5a2dbd989432bd.zip | |
GPU: Implement sampling multiple textures in the generated glsl shaders.
All tested games that use a single texture show no regression.
Only Texture2D textures are supported right now, each shader gets its own "tex_fs/vs/gs" sampler array to maintain independent textures between shader stages, the textures themselves are reused if possible.
Diffstat (limited to '')
| -rw-r--r-- | src/video_core/engines/maxwell_3d.cpp | 34 | ||||
| -rw-r--r-- | src/video_core/engines/maxwell_3d.h | 3 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 83 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 14 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 45 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.h | 40 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_manager.cpp | 19 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_manager.h | 1 |
9 files changed, 172 insertions, 69 deletions
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index ef12d9300..86e9dc998 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -354,6 +354,40 @@ std::vector<Texture::FullTextureInfo> Maxwell3D::GetStageTextures(Regs::ShaderSt | |||
| 354 | return textures; | 354 | return textures; |
| 355 | } | 355 | } |
| 356 | 356 | ||
| 357 | Texture::FullTextureInfo Maxwell3D::GetStageTexture(Regs::ShaderStage stage, size_t offset) const { | ||
| 358 | auto& shader = state.shader_stages[static_cast<size_t>(stage)]; | ||
| 359 | auto& tex_info_buffer = shader.const_buffers[regs.tex_cb_index]; | ||
| 360 | ASSERT(tex_info_buffer.enabled && tex_info_buffer.address != 0); | ||
| 361 | |||
| 362 | GPUVAddr tex_info_address = tex_info_buffer.address + offset * sizeof(Texture::TextureHandle); | ||
| 363 | |||
| 364 | ASSERT(tex_info_address < tex_info_buffer.address + tex_info_buffer.size); | ||
| 365 | |||
| 366 | boost::optional<VAddr> tex_address_cpu = memory_manager.GpuToCpuAddress(tex_info_address); | ||
| 367 | Texture::TextureHandle tex_handle{Memory::Read32(*tex_address_cpu)}; | ||
| 368 | |||
| 369 | Texture::FullTextureInfo tex_info{}; | ||
| 370 | tex_info.index = static_cast<u32>(offset); | ||
| 371 | |||
| 372 | // Load the TIC data. | ||
| 373 | if (tex_handle.tic_id != 0) { | ||
| 374 | tex_info.enabled = true; | ||
| 375 | |||
| 376 | auto tic_entry = GetTICEntry(tex_handle.tic_id); | ||
| 377 | // TODO(Subv): Workaround for BitField's move constructor being deleted. | ||
| 378 | std::memcpy(&tex_info.tic, &tic_entry, sizeof(tic_entry)); | ||
| 379 | } | ||
| 380 | |||
| 381 | // Load the TSC data | ||
| 382 | if (tex_handle.tsc_id != 0) { | ||
| 383 | auto tsc_entry = GetTSCEntry(tex_handle.tsc_id); | ||
| 384 | // TODO(Subv): Workaround for BitField's move constructor being deleted. | ||
| 385 | std::memcpy(&tex_info.tsc, &tsc_entry, sizeof(tsc_entry)); | ||
| 386 | } | ||
| 387 | |||
| 388 | return tex_info; | ||
| 389 | } | ||
| 390 | |||
| 357 | u32 Maxwell3D::GetRegisterValue(u32 method) const { | 391 | u32 Maxwell3D::GetRegisterValue(u32 method) const { |
| 358 | ASSERT_MSG(method < Regs::NUM_REGS, "Invalid Maxwell3D register"); | 392 | ASSERT_MSG(method < Regs::NUM_REGS, "Invalid Maxwell3D register"); |
| 359 | return regs.reg_array[method]; | 393 | return regs.reg_array[method]; |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 245410c95..56b837372 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -664,6 +664,9 @@ public: | |||
| 664 | /// Returns a list of enabled textures for the specified shader stage. | 664 | /// Returns a list of enabled textures for the specified shader stage. |
| 665 | std::vector<Texture::FullTextureInfo> GetStageTextures(Regs::ShaderStage stage) const; | 665 | std::vector<Texture::FullTextureInfo> GetStageTextures(Regs::ShaderStage stage) const; |
| 666 | 666 | ||
| 667 | /// Returns the texture information for a specific texture in a specific shader stage. | ||
| 668 | Texture::FullTextureInfo GetStageTexture(Regs::ShaderStage stage, size_t offset) const; | ||
| 669 | |||
| 667 | /// Returns whether the specified shader stage is enabled or not. | 670 | /// Returns whether the specified shader stage is enabled or not. |
| 668 | bool IsShaderStageEnabled(Regs::ShaderStage stage) const; | 671 | bool IsShaderStageEnabled(Regs::ShaderStage stage) const; |
| 669 | 672 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 0a33868b7..e9eb03ad9 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -196,8 +196,10 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) { | |||
| 196 | auto& gpu = Core::System().GetInstance().GPU().Maxwell3D(); | 196 | auto& gpu = Core::System().GetInstance().GPU().Maxwell3D(); |
| 197 | ASSERT_MSG(!gpu.regs.shader_config[0].enable, "VertexA is unsupported!"); | 197 | ASSERT_MSG(!gpu.regs.shader_config[0].enable, "VertexA is unsupported!"); |
| 198 | 198 | ||
| 199 | // Next available bindpoint to use when uploading the const buffers to the GLSL shaders. | 199 | // Next available bindpoints to use when uploading the const buffers and textures to the GLSL |
| 200 | // shaders. | ||
| 200 | u32 current_constbuffer_bindpoint = 0; | 201 | u32 current_constbuffer_bindpoint = 0; |
| 202 | u32 current_texture_bindpoint = 0; | ||
| 201 | 203 | ||
| 202 | for (unsigned index = 1; index < Maxwell::MaxShaderProgram; ++index) { | 204 | for (unsigned index = 1; index < Maxwell::MaxShaderProgram; ++index) { |
| 203 | auto& shader_config = gpu.regs.shader_config[index]; | 205 | auto& shader_config = gpu.regs.shader_config[index]; |
| @@ -258,6 +260,11 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) { | |||
| 258 | current_constbuffer_bindpoint = | 260 | current_constbuffer_bindpoint = |
| 259 | SetupConstBuffers(static_cast<Maxwell::ShaderStage>(stage), gl_stage_program, | 261 | SetupConstBuffers(static_cast<Maxwell::ShaderStage>(stage), gl_stage_program, |
| 260 | current_constbuffer_bindpoint, shader_resources.const_buffer_entries); | 262 | current_constbuffer_bindpoint, shader_resources.const_buffer_entries); |
| 263 | |||
| 264 | // Configure the textures for this shader stage. | ||
| 265 | current_texture_bindpoint = | ||
| 266 | SetupTextures(static_cast<Maxwell::ShaderStage>(stage), gl_stage_program, | ||
| 267 | current_texture_bindpoint, shader_resources.texture_samplers); | ||
| 261 | } | 268 | } |
| 262 | 269 | ||
| 263 | shader_program_manager->UseTrivialGeometryShader(); | 270 | shader_program_manager->UseTrivialGeometryShader(); |
| @@ -341,9 +348,6 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 341 | // TODO(bunnei): Sync framebuffer_scale uniform here | 348 | // TODO(bunnei): Sync framebuffer_scale uniform here |
| 342 | // TODO(bunnei): Sync scissorbox uniform(s) here | 349 | // TODO(bunnei): Sync scissorbox uniform(s) here |
| 343 | 350 | ||
| 344 | // Sync and bind the texture surfaces | ||
| 345 | BindTextures(); | ||
| 346 | |||
| 347 | // Viewport can have negative offsets or larger dimensions than our framebuffer sub-rect. Enable | 351 | // Viewport can have negative offsets or larger dimensions than our framebuffer sub-rect. Enable |
| 348 | // scissor test to prevent drawing outside of the framebuffer region | 352 | // scissor test to prevent drawing outside of the framebuffer region |
| 349 | state.scissor.enabled = true; | 353 | state.scissor.enabled = true; |
| @@ -447,39 +451,6 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 447 | } | 451 | } |
| 448 | } | 452 | } |
| 449 | 453 | ||
| 450 | void RasterizerOpenGL::BindTextures() { | ||
| 451 | using Regs = Tegra::Engines::Maxwell3D::Regs; | ||
| 452 | auto& maxwell3d = Core::System::GetInstance().GPU().Get3DEngine(); | ||
| 453 | |||
| 454 | // Each Maxwell shader stage can have an arbitrary number of textures, but we're limited to a | ||
| 455 | // certain number in OpenGL. We try to only use the minimum amount of host textures by not | ||
| 456 | // keeping a 1:1 relation between guest texture ids and host texture ids, ie, guest texture id 8 | ||
| 457 | // can be host texture id 0 if it's the only texture used in the guest shader program. | ||
| 458 | u32 host_texture_index = 0; | ||
| 459 | for (u32 stage = 0; stage < Regs::MaxShaderStage; ++stage) { | ||
| 460 | ASSERT(host_texture_index < texture_samplers.size()); | ||
| 461 | const auto textures = maxwell3d.GetStageTextures(static_cast<Regs::ShaderStage>(stage)); | ||
| 462 | for (unsigned texture_index = 0; texture_index < textures.size(); ++texture_index) { | ||
| 463 | const auto& texture = textures[texture_index]; | ||
| 464 | |||
| 465 | if (texture.enabled) { | ||
| 466 | texture_samplers[host_texture_index].SyncWithConfig(texture.tsc); | ||
| 467 | Surface surface = res_cache.GetTextureSurface(texture); | ||
| 468 | if (surface != nullptr) { | ||
| 469 | state.texture_units[host_texture_index].texture_2d = surface->texture.handle; | ||
| 470 | } else { | ||
| 471 | // Can occur when texture addr is null or its memory is unmapped/invalid | ||
| 472 | state.texture_units[texture_index].texture_2d = 0; | ||
| 473 | } | ||
| 474 | |||
| 475 | ++host_texture_index; | ||
| 476 | } else { | ||
| 477 | state.texture_units[texture_index].texture_2d = 0; | ||
| 478 | } | ||
| 479 | } | ||
| 480 | } | ||
| 481 | } | ||
| 482 | |||
| 483 | void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 method) { | 454 | void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 method) { |
| 484 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; | 455 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; |
| 485 | switch (method) { | 456 | switch (method) { |
| @@ -674,6 +645,44 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint progr | |||
| 674 | return current_bindpoint + entries.size(); | 645 | return current_bindpoint + entries.size(); |
| 675 | } | 646 | } |
| 676 | 647 | ||
| 648 | u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, GLuint program, u32 current_unit, | ||
| 649 | const std::vector<GLShader::SamplerEntry>& entries) { | ||
| 650 | auto& gpu = Core::System::GetInstance().GPU(); | ||
| 651 | auto& maxwell3d = gpu.Get3DEngine(); | ||
| 652 | |||
| 653 | ASSERT_MSG(maxwell3d.IsShaderStageEnabled(stage), | ||
| 654 | "Attempted to upload textures of disabled shader stage"); | ||
| 655 | |||
| 656 | ASSERT_MSG(current_unit + entries.size() <= std::size(state.texture_units), | ||
| 657 | "Exceeded the number of active textures."); | ||
| 658 | |||
| 659 | for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) { | ||
| 660 | const auto& entry = entries[bindpoint]; | ||
| 661 | u32 current_bindpoint = current_unit + bindpoint; | ||
| 662 | |||
| 663 | // Bind the uniform to the sampler. | ||
| 664 | GLint uniform = glGetUniformLocation(program, entry.GetName().c_str()); | ||
| 665 | ASSERT(uniform != -1); | ||
| 666 | glProgramUniform1i(program, uniform, current_bindpoint); | ||
| 667 | |||
| 668 | const auto texture = maxwell3d.GetStageTexture(entry.GetStage(), entry.GetOffset()); | ||
| 669 | ASSERT(texture.enabled); | ||
| 670 | |||
| 671 | texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); | ||
| 672 | Surface surface = res_cache.GetTextureSurface(texture); | ||
| 673 | if (surface != nullptr) { | ||
| 674 | state.texture_units[current_bindpoint].texture_2d = surface->texture.handle; | ||
| 675 | } else { | ||
| 676 | // Can occur when texture addr is null or its memory is unmapped/invalid | ||
| 677 | state.texture_units[current_bindpoint].texture_2d = 0; | ||
| 678 | } | ||
| 679 | } | ||
| 680 | |||
| 681 | state.Apply(); | ||
| 682 | |||
| 683 | return current_unit + entries.size(); | ||
| 684 | } | ||
| 685 | |||
| 677 | void RasterizerOpenGL::BindFramebufferSurfaces(const Surface& color_surface, | 686 | void RasterizerOpenGL::BindFramebufferSurfaces(const Surface& color_surface, |
| 678 | const Surface& depth_surface, bool has_stencil) { | 687 | const Surface& depth_surface, bool has_stencil) { |
| 679 | state.draw.draw_framebuffer = framebuffer.handle; | 688 | state.draw.draw_framebuffer = framebuffer.handle; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 4b915c76a..d3f0558ed 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -80,9 +80,6 @@ private: | |||
| 80 | void BindFramebufferSurfaces(const Surface& color_surface, const Surface& depth_surface, | 80 | void BindFramebufferSurfaces(const Surface& color_surface, const Surface& depth_surface, |
| 81 | bool has_stencil); | 81 | bool has_stencil); |
| 82 | 82 | ||
| 83 | /// Binds the required textures to OpenGL before drawing a batch. | ||
| 84 | void BindTextures(); | ||
| 85 | |||
| 86 | /* | 83 | /* |
| 87 | * Configures the current constbuffers to use for the draw command. | 84 | * Configures the current constbuffers to use for the draw command. |
| 88 | * @param stage The shader stage to configure buffers for. | 85 | * @param stage The shader stage to configure buffers for. |
| @@ -95,6 +92,17 @@ private: | |||
| 95 | u32 current_bindpoint, | 92 | u32 current_bindpoint, |
| 96 | const std::vector<GLShader::ConstBufferEntry>& entries); | 93 | const std::vector<GLShader::ConstBufferEntry>& entries); |
| 97 | 94 | ||
| 95 | /* | ||
| 96 | * Configures the current textures to use for the draw command. | ||
| 97 | * @param stage The shader stage to configure textures for. | ||
| 98 | * @param program The OpenGL program object that contains the specified stage. | ||
| 99 | * @param current_unit The offset at which to start counting unused texture units. | ||
| 100 | * @param entries Vector describing the textures that are actually used in the guest shader. | ||
| 101 | * @returns The next available bindpoint for use in the next shader stage. | ||
| 102 | */ | ||
| 103 | u32 SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, GLuint program, | ||
| 104 | u32 current_unit, const std::vector<GLShader::SamplerEntry>& entries); | ||
| 105 | |||
| 98 | /// Syncs the viewport to match the guest state | 106 | /// Syncs the viewport to match the guest state |
| 99 | void SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect, u16 res_scale); | 107 | void SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect, u16 res_scale); |
| 100 | 108 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 7a59ecccf..15288bd57 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -425,6 +425,14 @@ public: | |||
| 425 | ++const_buffer_layout; | 425 | ++const_buffer_layout; |
| 426 | } | 426 | } |
| 427 | declarations.AddNewLine(); | 427 | declarations.AddNewLine(); |
| 428 | |||
| 429 | // Append the sampler2D array for the used textures. | ||
| 430 | size_t num_samplers = GetSamplers().size(); | ||
| 431 | if (num_samplers > 0) { | ||
| 432 | declarations.AddLine("uniform sampler2D " + SamplerEntry::GetArrayName(stage) + '[' + | ||
| 433 | std::to_string(num_samplers) + "];"); | ||
| 434 | declarations.AddNewLine(); | ||
| 435 | } | ||
| 428 | } | 436 | } |
| 429 | 437 | ||
| 430 | /// Returns a list of constant buffer declarations | 438 | /// Returns a list of constant buffer declarations |
| @@ -435,6 +443,32 @@ public: | |||
| 435 | return result; | 443 | return result; |
| 436 | } | 444 | } |
| 437 | 445 | ||
| 446 | /// Returns a list of samplers used in the shader | ||
| 447 | std::vector<SamplerEntry> GetSamplers() const { | ||
| 448 | return used_samplers; | ||
| 449 | } | ||
| 450 | |||
| 451 | /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if | ||
| 452 | /// necessary. | ||
| 453 | std::string AccessSampler(const Sampler& sampler) { | ||
| 454 | size_t offset = static_cast<size_t>(sampler.index.Value()); | ||
| 455 | |||
| 456 | // If this sampler has already been used, return the existing mapping. | ||
| 457 | auto itr = | ||
| 458 | std::find_if(used_samplers.begin(), used_samplers.end(), | ||
| 459 | [&](const SamplerEntry& entry) { return entry.GetOffset() == offset; }); | ||
| 460 | |||
| 461 | if (itr != used_samplers.end()) { | ||
| 462 | return itr->GetName(); | ||
| 463 | } | ||
| 464 | |||
| 465 | // Otherwise create a new mapping for this sampler | ||
| 466 | size_t next_index = used_samplers.size(); | ||
| 467 | SamplerEntry entry{stage, offset, next_index}; | ||
| 468 | used_samplers.emplace_back(entry); | ||
| 469 | return entry.GetName(); | ||
| 470 | } | ||
| 471 | |||
| 438 | private: | 472 | private: |
| 439 | /// Build GLSL conversion function, e.g. floatBitsToInt, intBitsToFloat, etc. | 473 | /// Build GLSL conversion function, e.g. floatBitsToInt, intBitsToFloat, etc. |
| 440 | const std::string GetGLSLConversionFunc(GLSLRegister::Type src, GLSLRegister::Type dest) const { | 474 | const std::string GetGLSLConversionFunc(GLSLRegister::Type src, GLSLRegister::Type dest) const { |
| @@ -544,6 +578,7 @@ private: | |||
| 544 | std::set<Attribute::Index> declr_input_attribute; | 578 | std::set<Attribute::Index> declr_input_attribute; |
| 545 | std::set<Attribute::Index> declr_output_attribute; | 579 | std::set<Attribute::Index> declr_output_attribute; |
| 546 | std::array<ConstBufferEntry, Maxwell3D::Regs::MaxConstBuffers> declr_const_buffers; | 580 | std::array<ConstBufferEntry, Maxwell3D::Regs::MaxConstBuffers> declr_const_buffers; |
| 581 | std::vector<SamplerEntry> used_samplers; | ||
| 547 | const Maxwell3D::Regs::ShaderStage& stage; | 582 | const Maxwell3D::Regs::ShaderStage& stage; |
| 548 | }; | 583 | }; |
| 549 | 584 | ||
| @@ -563,7 +598,7 @@ public: | |||
| 563 | 598 | ||
| 564 | /// Returns entries in the shader that are useful for external functions | 599 | /// Returns entries in the shader that are useful for external functions |
| 565 | ShaderEntries GetEntries() const { | 600 | ShaderEntries GetEntries() const { |
| 566 | return {regs.GetConstBuffersDeclarations()}; | 601 | return {regs.GetConstBuffersDeclarations(), regs.GetSamplers()}; |
| 567 | } | 602 | } |
| 568 | 603 | ||
| 569 | private: | 604 | private: |
| @@ -585,12 +620,8 @@ private: | |||
| 585 | } | 620 | } |
| 586 | 621 | ||
| 587 | /// Generates code representing a texture sampler. | 622 | /// Generates code representing a texture sampler. |
| 588 | std::string GetSampler(const Sampler& sampler) const { | 623 | std::string GetSampler(const Sampler& sampler) { |
| 589 | // TODO(Subv): Support more than just texture sampler 0 | 624 | return regs.AccessSampler(sampler); |
| 590 | ASSERT_MSG(sampler.index == Sampler::Index::Sampler_0, "unsupported"); | ||
| 591 | const unsigned index{static_cast<unsigned>(sampler.index.Value()) - | ||
| 592 | static_cast<unsigned>(Sampler::Index::Sampler_0)}; | ||
| 593 | return "tex[" + std::to_string(index) + ']'; | ||
| 594 | } | 625 | } |
| 595 | 626 | ||
| 596 | /** | 627 | /** |
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 254f6e2c3..b88d592b7 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp | |||
| @@ -62,8 +62,6 @@ layout (std140) uniform fs_config { | |||
| 62 | vec4 viewport_flip; | 62 | vec4 viewport_flip; |
| 63 | }; | 63 | }; |
| 64 | 64 | ||
| 65 | uniform sampler2D tex[32]; | ||
| 66 | |||
| 67 | void main() { | 65 | void main() { |
| 68 | exec_shader(); | 66 | exec_shader(); |
| 69 | } | 67 | } |
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h index 458032b5c..e8b78934c 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.h +++ b/src/video_core/renderer_opengl/gl_shader_gen.h | |||
| @@ -56,8 +56,48 @@ private: | |||
| 56 | Maxwell::ShaderStage stage; | 56 | Maxwell::ShaderStage stage; |
| 57 | }; | 57 | }; |
| 58 | 58 | ||
| 59 | class SamplerEntry { | ||
| 60 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; | ||
| 61 | |||
| 62 | public: | ||
| 63 | SamplerEntry(Maxwell::ShaderStage stage, size_t offset, size_t index) | ||
| 64 | : offset(offset), stage(stage), sampler_index(index) {} | ||
| 65 | |||
| 66 | size_t GetOffset() const { | ||
| 67 | return offset; | ||
| 68 | } | ||
| 69 | |||
| 70 | size_t GetIndex() const { | ||
| 71 | return sampler_index; | ||
| 72 | } | ||
| 73 | |||
| 74 | Maxwell::ShaderStage GetStage() const { | ||
| 75 | return stage; | ||
| 76 | } | ||
| 77 | |||
| 78 | std::string GetName() const { | ||
| 79 | return std::string(TextureSamplerNames[static_cast<size_t>(stage)]) + '[' + | ||
| 80 | std::to_string(sampler_index) + ']'; | ||
| 81 | } | ||
| 82 | |||
| 83 | static std::string GetArrayName(Maxwell::ShaderStage stage) { | ||
| 84 | return TextureSamplerNames[static_cast<size_t>(stage)]; | ||
| 85 | } | ||
| 86 | |||
| 87 | private: | ||
| 88 | static constexpr std::array<const char*, Maxwell::MaxShaderStage> TextureSamplerNames = { | ||
| 89 | "tex_vs", "tex_tessc", "tex_tesse", "tex_gs", "tex_fs", | ||
| 90 | }; | ||
| 91 | /// Offset in TSC memory from which to read the sampler object, as specified by the sampling | ||
| 92 | /// instruction. | ||
| 93 | size_t offset; | ||
| 94 | Maxwell::ShaderStage stage; ///< Shader stage where this sampler was used. | ||
| 95 | size_t sampler_index; ///< Value used to index into the generated GLSL sampler array. | ||
| 96 | }; | ||
| 97 | |||
| 59 | struct ShaderEntries { | 98 | struct ShaderEntries { |
| 60 | std::vector<ConstBufferEntry> const_buffer_entries; | 99 | std::vector<ConstBufferEntry> const_buffer_entries; |
| 100 | std::vector<SamplerEntry> texture_samplers; | ||
| 61 | }; | 101 | }; |
| 62 | 102 | ||
| 63 | using ProgramResult = std::pair<std::string, ShaderEntries>; | 103 | using ProgramResult = std::pair<std::string, ShaderEntries>; |
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp index ccdfc2718..7c00beb33 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.cpp +++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp | |||
| @@ -32,25 +32,6 @@ void SetShaderUniformBlockBindings(GLuint shader) { | |||
| 32 | sizeof(MaxwellUniformData)); | 32 | sizeof(MaxwellUniformData)); |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | void SetShaderSamplerBindings(GLuint shader) { | ||
| 36 | OpenGLState cur_state = OpenGLState::GetCurState(); | ||
| 37 | GLuint old_program = std::exchange(cur_state.draw.shader_program, shader); | ||
| 38 | cur_state.Apply(); | ||
| 39 | |||
| 40 | // Set the texture samplers to correspond to different texture units | ||
| 41 | for (u32 texture = 0; texture < NumTextureSamplers; ++texture) { | ||
| 42 | // Set the texture samplers to correspond to different texture units | ||
| 43 | std::string uniform_name = "tex[" + std::to_string(texture) + "]"; | ||
| 44 | GLint uniform_tex = glGetUniformLocation(shader, uniform_name.c_str()); | ||
| 45 | if (uniform_tex != -1) { | ||
| 46 | glUniform1i(uniform_tex, TextureUnits::MaxwellTexture(texture).id); | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | cur_state.draw.shader_program = old_program; | ||
| 51 | cur_state.Apply(); | ||
| 52 | } | ||
| 53 | |||
| 54 | } // namespace Impl | 35 | } // namespace Impl |
| 55 | 36 | ||
| 56 | void MaxwellUniformData::SetFromRegs(const Maxwell3D::State::ShaderStageInfo& shader_stage) { | 37 | void MaxwellUniformData::SetFromRegs(const Maxwell3D::State::ShaderStageInfo& shader_stage) { |
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index e963b4b7e..4295c20a6 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h | |||
| @@ -45,7 +45,6 @@ public: | |||
| 45 | shader.Create(program_result.first.c_str(), type); | 45 | shader.Create(program_result.first.c_str(), type); |
| 46 | program.Create(true, shader.handle); | 46 | program.Create(true, shader.handle); |
| 47 | Impl::SetShaderUniformBlockBindings(program.handle); | 47 | Impl::SetShaderUniformBlockBindings(program.handle); |
| 48 | Impl::SetShaderSamplerBindings(program.handle); | ||
| 49 | entries = program_result.second; | 48 | entries = program_result.second; |
| 50 | } | 49 | } |
| 51 | GLuint GetHandle() const { | 50 | GLuint GetHandle() const { |