summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2015-11-15 17:43:01 -0500
committerGravatar bunnei2016-02-05 17:17:31 -0500
commit021cb0bced1d8045f04b85024b97a07a4d0df12f (patch)
treeaf2e041a2625ebde8c5f734f2e0ab911aba11625 /src
parentrenderer_opengl: Initial implementation of basic specular lighting. (diff)
downloadyuzu-021cb0bced1d8045f04b85024b97a07a4d0df12f.tar.gz
yuzu-021cb0bced1d8045f04b85024b97a07a4d0df12f.tar.xz
yuzu-021cb0bced1d8045f04b85024b97a07a4d0df12f.zip
renderer_opengl: Use textures for fragment shader LUTs instead of UBOs.
- Gets us LUT interpolation for free. - Some older Intel GPU drivers did not support the big UBOs needed to store the LUTs.
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp51
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h10
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp18
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp8
-rw-r--r--src/video_core/renderer_opengl/gl_state.h4
5 files changed, 64 insertions, 27 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index c6fb37c53..6e7d6a40d 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -126,6 +126,19 @@ void RasterizerOpenGL::InitObjects() {
126 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb_color_texture.texture.handle, 0); 126 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb_color_texture.texture.handle, 0);
127 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, fb_depth_texture.texture.handle, 0); 127 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, fb_depth_texture.texture.handle, 0);
128 128
129 for (size_t i = 0; i < lighting_lut.size(); ++i) {
130 lighting_lut[i].Create();
131 state.lighting_lut[i].texture_1d = lighting_lut[i].handle;
132
133 glActiveTexture(GL_TEXTURE3 + i);
134 glBindTexture(GL_TEXTURE_1D, state.lighting_lut[i].texture_1d);
135
136 glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, 256, 0, GL_RGBA, GL_FLOAT, nullptr);
137 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
138 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
139 }
140 state.Apply();
141
129 ASSERT_MSG(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, 142 ASSERT_MSG(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE,
130 "OpenGL rasterizer framebuffer setup failed, status %X", glCheckFramebufferStatus(GL_FRAMEBUFFER)); 143 "OpenGL rasterizer framebuffer setup failed, status %X", glCheckFramebufferStatus(GL_FRAMEBUFFER));
131} 144}
@@ -162,7 +175,7 @@ void RasterizerOpenGL::DrawTriangles() {
162 state.draw.shader_dirty = false; 175 state.draw.shader_dirty = false;
163 } 176 }
164 177
165 for (unsigned index = 0; index < Pica::g_state.lighting.luts.size(); index++) { 178 for (unsigned index = 0; index < lighting_lut.size(); index++) {
166 if (uniform_block_data.lut_dirty[index]) { 179 if (uniform_block_data.lut_dirty[index]) {
167 SyncLightingLUT(index); 180 SyncLightingLUT(index);
168 uniform_block_data.lut_dirty[index] = false; 181 uniform_block_data.lut_dirty[index] = false;
@@ -451,7 +464,7 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
451 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[7], 0x1cf): 464 case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[7], 0x1cf):
452 { 465 {
453 auto& lut_config = regs.lighting.lut_config; 466 auto& lut_config = regs.lighting.lut_config;
454 uniform_block_data.lut_dirty[lut_config.type] = true; 467 uniform_block_data.lut_dirty[lut_config.type / 4] = true;
455 break; 468 break;
456 } 469 }
457 470
@@ -663,6 +676,20 @@ void RasterizerOpenGL::SetShader() {
663 uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[2]"); 676 uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[2]");
664 if (uniform_tex != -1) { glUniform1i(uniform_tex, 2); } 677 if (uniform_tex != -1) { glUniform1i(uniform_tex, 2); }
665 678
679 // Set the texture samplers to correspond to different lookup table texture units
680 GLuint uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[0]");
681 if (uniform_lut != -1) { glUniform1i(uniform_lut, 3); }
682 uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[1]");
683 if (uniform_lut != -1) { glUniform1i(uniform_lut, 4); }
684 uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[2]");
685 if (uniform_lut != -1) { glUniform1i(uniform_lut, 5); }
686 uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[3]");
687 if (uniform_lut != -1) { glUniform1i(uniform_lut, 6); }
688 uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[4]");
689 if (uniform_lut != -1) { glUniform1i(uniform_lut, 7); }
690 uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[5]");
691 if (uniform_lut != -1) { glUniform1i(uniform_lut, 8); }
692
666 current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get(); 693 current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get();
667 694
668 unsigned int block_index = glGetUniformBlockIndex(current_shader->shader.handle, "shader_data"); 695 unsigned int block_index = glGetUniformBlockIndex(current_shader->shader.handle, "shader_data");
@@ -675,9 +702,6 @@ void RasterizerOpenGL::SetShader() {
675 for (int index = 0; index < tev_stages.size(); ++index) 702 for (int index = 0; index < tev_stages.size(); ++index)
676 SyncTevConstColor(index, tev_stages[index]); 703 SyncTevConstColor(index, tev_stages[index]);
677 704
678 for (unsigned index = 0; index < Pica::g_state.lighting.luts.size(); ++index)
679 SyncLightingLUT(index);
680
681 SyncGlobalAmbient(); 705 SyncGlobalAmbient();
682 for (int light_index = 0; light_index < 8; light_index++) { 706 for (int light_index = 0; light_index < 8; light_index++) {
683 SyncLightDiffuse(light_index); 707 SyncLightDiffuse(light_index);
@@ -874,16 +898,19 @@ void RasterizerOpenGL::SyncGlobalAmbient() {
874} 898}
875 899
876void RasterizerOpenGL::SyncLightingLUT(unsigned lut_index) { 900void RasterizerOpenGL::SyncLightingLUT(unsigned lut_index) {
877 auto& lut = uniform_block_data.data.lighting_lut[lut_index / 4]; 901 std::array<std::array<GLfloat, 4>, 256> new_data;
878 std::array<std::array<GLfloat, 4>, 256> new_lut;
879 902
880 for (int offset = 0; offset < new_lut.size(); ++offset) { 903 for (unsigned offset = 0; offset < new_data.size(); ++offset) {
881 new_lut[offset][lut_index & 3] = Pica::g_state.lighting.luts[lut_index][offset].ToFloat(); 904 new_data[offset][0] = Pica::g_state.lighting.luts[(lut_index * 4) + 0][offset].ToFloat();
905 new_data[offset][1] = Pica::g_state.lighting.luts[(lut_index * 4) + 1][offset].ToFloat();
906 new_data[offset][2] = Pica::g_state.lighting.luts[(lut_index * 4) + 2][offset].ToFloat();
907 new_data[offset][3] = Pica::g_state.lighting.luts[(lut_index * 4) + 3][offset].ToFloat();
882 } 908 }
883 909
884 if (new_lut != lut) { 910 if (new_data != lighting_lut_data[lut_index]) {
885 lut = new_lut; 911 lighting_lut_data[lut_index] = new_data;
886 uniform_block_data.dirty = true; 912 glActiveTexture(GL_TEXTURE3 + lut_index);
913 glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_RGBA, GL_FLOAT, lighting_lut_data[lut_index].data());
887 } 914 }
888} 915}
889 916
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 9e93b8b2f..b50542701 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -264,11 +264,10 @@ private:
264 std::array<GLfloat, 3> lighting_global_ambient; 264 std::array<GLfloat, 3> lighting_global_ambient;
265 INSERT_PADDING_WORDS(1); 265 INSERT_PADDING_WORDS(1);
266 LightSrc light_src[8]; 266 LightSrc light_src[8];
267 std::array<std::array<std::array<GLfloat, 4>, 256>, 6> lighting_lut;
268 }; 267 };
269 268
270 static_assert(sizeof(UniformData) == 0x6210, "The size of the UniformData structure has changed, update the structure in the shader"); 269 static_assert(sizeof(UniformData) == 0x310, "The size of the UniformData structure has changed, update the structure in the shader");
271 static_assert(sizeof(UniformData) < 32768, "UniformData structure must be less than 32kb"); 270 static_assert(sizeof(UniformData) < 16384, "UniformData structure must be less than 16kb as per the OpenGL spec");
272 271
273 /// Reconfigure the OpenGL color texture to use the given format and dimensions 272 /// Reconfigure the OpenGL color texture to use the given format and dimensions
274 void ReconfigureColorTexture(TextureInfo& texture, Pica::Regs::ColorFormat format, u32 width, u32 height); 273 void ReconfigureColorTexture(TextureInfo& texture, Pica::Regs::ColorFormat format, u32 width, u32 height);
@@ -378,7 +377,7 @@ private:
378 377
379 struct { 378 struct {
380 UniformData data; 379 UniformData data;
381 bool lut_dirty[24]; 380 bool lut_dirty[6];
382 bool dirty; 381 bool dirty;
383 } uniform_block_data; 382 } uniform_block_data;
384 383
@@ -386,4 +385,7 @@ private:
386 OGLBuffer vertex_buffer; 385 OGLBuffer vertex_buffer;
387 OGLBuffer uniform_buffer; 386 OGLBuffer uniform_buffer;
388 OGLFramebuffer framebuffer; 387 OGLFramebuffer framebuffer;
388
389 std::array<OGLTexture, 6> lighting_lut;
390 std::array<std::array<std::array<GLfloat, 4>, 256>, 6> lighting_lut_data;
389}; 391};
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index abcc89f1d..cb570c4d2 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -324,6 +324,7 @@ std::string GenerateFragmentShader(const PicaShaderConfig& config) {
324#define NUM_TEV_STAGES 6 324#define NUM_TEV_STAGES 6
325#define NUM_LIGHTS 8 325#define NUM_LIGHTS 8
326#define LIGHTING_LUT_SIZE 256 326#define LIGHTING_LUT_SIZE 256
327#define FLOAT_255 0.99609375
327 328
328in vec4 primary_color; 329in vec4 primary_color;
329in vec2 texcoord[3]; 330in vec2 texcoord[3];
@@ -347,15 +348,10 @@ layout (std140) uniform shader_data {
347 float depth_offset; 348 float depth_offset;
348 vec3 lighting_global_ambient; 349 vec3 lighting_global_ambient;
349 LightSrc light_src[NUM_LIGHTS]; 350 LightSrc light_src[NUM_LIGHTS];
350 vec4 lighting_lut_0[LIGHTING_LUT_SIZE];
351 vec4 lighting_lut_1[LIGHTING_LUT_SIZE];
352 vec4 lighting_lut_2[LIGHTING_LUT_SIZE];
353 vec4 lighting_lut_3[LIGHTING_LUT_SIZE];
354 vec4 lighting_lut_4[LIGHTING_LUT_SIZE];
355 vec4 lighting_lut_5[LIGHTING_LUT_SIZE];
356}; 351};
357 352
358uniform sampler2D tex[3]; 353uniform sampler2D tex[3];
354uniform sampler1D lut[6];
359 355
360void main() { 356void main() {
361vec4 primary_fragment_color = vec4(0.0); 357vec4 primary_fragment_color = vec4(0.0);
@@ -404,11 +400,11 @@ vec4 secondary_fragment_color = vec4(0.0);
404 if (abs) { 400 if (abs) {
405 // In the range of [ 0.f, 1.f] 401 // In the range of [ 0.f, 1.f]
406 index = config.light_src[light_num].two_sided_diffuse ? "abs(" + index + ")" : "max(" + index + ", 0.f)"; 402 index = config.light_src[light_num].two_sided_diffuse ? "abs(" + index + ")" : "max(" + index + ", 0.f)";
407 return "clamp(int(" + index + " * 256.0), 0, 255)"; 403 return "clamp(" + index + ", 0.0, FLOAT_255)";
408 } else { 404 } else {
409 // In the range of [-1.f, 1.f] 405 // In the range of [-1.f, 1.f]
410 index = "clamp(" + index + ", -1.0, 1.0)"; 406 index = "clamp(" + index + ", -1.0, 1.0)";
411 return std::string("uint(int(" + index + " * 127.f) & 0xff)"); 407 return "clamp(((" + index + " < 0) ? " + index + " + 2.0 : " + index + ") / 2.0, 0.0, FLOAT_255)";
412 } 408 }
413 409
414 return std::string(); 410 return std::string();
@@ -435,10 +431,10 @@ vec4 secondary_fragment_color = vec4(0.0);
435 std::string scale = std::to_string(config.light_src[light_index].dist_atten_scale); 431 std::string scale = std::to_string(config.light_src[light_index].dist_atten_scale);
436 std::string bias = std::to_string(config.light_src[light_index].dist_atten_bias); 432 std::string bias = std::to_string(config.light_src[light_index].dist_atten_bias);
437 std::string lut_index = "(" + scale + " * length(fragment_position - " + light_src + ".position) + " + bias + ")"; 433 std::string lut_index = "(" + scale + " * length(fragment_position - " + light_src + ".position) + " + bias + ")";
438 std::string clamped_lut_index = "((clamp(int(" + lut_index + " * 256.0), 0, 255)))"; 434 std::string clamped_lut_index = "((clamp(" + lut_index + ", 0.0, FLOAT_255)))";
439 435
440 const unsigned lut_num = ((unsigned)Regs::LightingSampler::DistanceAttenuation + num); 436 const unsigned lut_num = ((unsigned)Regs::LightingSampler::DistanceAttenuation + num);
441 out += "dist_atten = lighting_lut_" + std::to_string(lut_num / 4) + "[" + clamped_lut_index + "][" + std::to_string(lut_num & 3) + "];\n"; 437 out += "dist_atten = texture(lut[" + std::to_string(lut_num / 4) + "], " + clamped_lut_index + ")[" + std::to_string(lut_num & 3) + "];\n";
442 } 438 }
443 439
444 // Compute primary fragment color (diffuse lighting) function 440 // Compute primary fragment color (diffuse lighting) function
@@ -447,7 +443,7 @@ vec4 secondary_fragment_color = vec4(0.0);
447 // Compute secondary fragment color (specular lighting) function 443 // Compute secondary fragment color (specular lighting) function
448 std::string clamped_lut_index = GetLutIndex(num, config.lighting_lut.d0_type, config.lighting_lut.d0_abs); 444 std::string clamped_lut_index = GetLutIndex(num, config.lighting_lut.d0_type, config.lighting_lut.d0_abs);
449 const unsigned lut_num = (unsigned)Regs::LightingSampler::Distribution0; 445 const unsigned lut_num = (unsigned)Regs::LightingSampler::Distribution0;
450 std::string lut_lookup = "lighting_lut_" + std::to_string(lut_num / 4) + "[" + clamped_lut_index + "][" + std::to_string(lut_num & 3) + "]"; 446 std::string lut_lookup = "texture(lut[" + std::to_string(lut_num / 4) + "], " + clamped_lut_index + ")[" + std::to_string(lut_num & 3) + "]";
451 447
452 out += "specular_sum += (" + lut_lookup + " * light_src[" + std::to_string(num) + "].specular_0 * dist_atten);\n"; 448 out += "specular_sum += (" + lut_lookup + " * light_src[" + std::to_string(num) + "].specular_0 * dist_atten);\n";
453 } 449 }
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index a82372995..ab4b6c7b1 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -170,6 +170,14 @@ void OpenGLState::Apply() {
170 } 170 }
171 } 171 }
172 172
173 // Lighting LUTs
174 for (unsigned i = 0; i < ARRAY_SIZE(lighting_lut); ++i) {
175 if (lighting_lut[i].texture_1d != cur_state.lighting_lut[i].texture_1d) {
176 glActiveTexture(GL_TEXTURE3 + i);
177 glBindTexture(GL_TEXTURE_1D, lighting_lut[i].texture_1d);
178 }
179 }
180
173 // Framebuffer 181 // Framebuffer
174 if (draw.framebuffer != cur_state.draw.framebuffer) { 182 if (draw.framebuffer != cur_state.draw.framebuffer) {
175 glBindFramebuffer(GL_FRAMEBUFFER, draw.framebuffer); 183 glBindFramebuffer(GL_FRAMEBUFFER, draw.framebuffer);
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index b8ab45bb8..e848058d7 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -62,6 +62,10 @@ public:
62 } texture_units[3]; 62 } texture_units[3];
63 63
64 struct { 64 struct {
65 GLuint texture_1d; // GL_TEXTURE_BINDING_1D
66 } lighting_lut[6];
67
68 struct {
65 GLuint framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING 69 GLuint framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING
66 GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING 70 GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING
67 GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING 71 GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING