summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/video_core/engines/maxwell_3d.cpp34
-rw-r--r--src/video_core/engines/maxwell_3d.h3
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp83
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h14
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp45
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.h40
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.cpp19
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.h1
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
357Texture::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
357u32 Maxwell3D::GetRegisterValue(u32 method) const { 391u32 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
450void 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
483void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 method) { 454void 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
648u32 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
677void RasterizerOpenGL::BindFramebufferSurfaces(const Surface& color_surface, 686void 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
438private: 472private:
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
569private: 604private:
@@ -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
65uniform sampler2D tex[32];
66
67void main() { 65void 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
59class SamplerEntry {
60 using Maxwell = Tegra::Engines::Maxwell3D::Regs;
61
62public:
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
87private:
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
59struct ShaderEntries { 98struct 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
63using ProgramResult = std::pair<std::string, ShaderEntries>; 103using 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
35void 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
56void MaxwellUniformData::SetFromRegs(const Maxwell3D::State::ShaderStageInfo& shader_stage) { 37void 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 {