summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2015-11-14 23:23:08 -0500
committerGravatar bunnei2016-02-05 17:17:30 -0500
commitbf89870437ebb0d983cfc20c3ac0490169f59f44 (patch)
tree8bf0f8121c02e66fd5aeeff8cacb7e288c84ae90 /src
parentrenderer_opengl: Implement HW fragment lighting distance attenuation. (diff)
downloadyuzu-bf89870437ebb0d983cfc20c3ac0490169f59f44.tar.gz
yuzu-bf89870437ebb0d983cfc20c3ac0490169f59f44.tar.xz
yuzu-bf89870437ebb0d983cfc20c3ac0490169f59f44.zip
renderer_opengl: Initial implementation of basic specular lighting.
Diffstat (limited to 'src')
-rw-r--r--src/video_core/pica.h8
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp68
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h20
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp82
4 files changed, 165 insertions, 13 deletions
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index aad9effdc..c63d87a36 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -659,6 +659,8 @@ struct Regs {
659 659
660 enum class LightingLutInput { 660 enum class LightingLutInput {
661 NH = 0, // Cosine of the angle between the normal and half-angle vectors 661 NH = 0, // Cosine of the angle between the normal and half-angle vectors
662 VH = 1, // Cosine of the angle between the view and half-angle vectors
663 NV = 2, // Cosine of the angle between the normal and the view vector
662 LN = 3, // Cosine of the angle between the light and the normal vectors 664 LN = 3, // Cosine of the angle between the light and the normal vectors
663 }; 665 };
664 666
@@ -709,7 +711,11 @@ struct Regs {
709 LightColor global_ambient; // emission + (material.ambient * lighting.ambient) 711 LightColor global_ambient; // emission + (material.ambient * lighting.ambient)
710 INSERT_PADDING_WORDS(0x1); 712 INSERT_PADDING_WORDS(0x1);
711 BitField<0, 3, u32> src_num; // number of enabled lights - 1 713 BitField<0, 3, u32> src_num; // number of enabled lights - 1
712 INSERT_PADDING_WORDS(0x1); 714
715 union {
716 BitField< 4, 4, u32> config;
717 BitField<27, 1, u32> clamp_highlights;
718 } light_env;
713 719
714 union { 720 union {
715 // Each bit specifies whether distance attenuation should be applied for the 721 // Each bit specifies whether distance attenuation should be applied for the
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 80693fa29..c6fb37c53 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -297,6 +297,58 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
297 SyncCombinerColor(); 297 SyncCombinerColor();
298 break; 298 break;
299 299
300 // Fragment lighting specular 0 color
301 case PICA_REG_INDEX_WORKAROUND(lighting.light[0].specular_0, 0x140 + 0 * 0x10):
302 SyncLightSpecular0(0);
303 break;
304 case PICA_REG_INDEX_WORKAROUND(lighting.light[1].specular_0, 0x140 + 1 * 0x10):
305 SyncLightSpecular0(1);
306 break;
307 case PICA_REG_INDEX_WORKAROUND(lighting.light[2].specular_0, 0x140 + 2 * 0x10):
308 SyncLightSpecular0(2);
309 break;
310 case PICA_REG_INDEX_WORKAROUND(lighting.light[3].specular_0, 0x140 + 3 * 0x10):
311 SyncLightSpecular0(3);
312 break;
313 case PICA_REG_INDEX_WORKAROUND(lighting.light[4].specular_0, 0x140 + 4 * 0x10):
314 SyncLightSpecular0(4);
315 break;
316 case PICA_REG_INDEX_WORKAROUND(lighting.light[5].specular_0, 0x140 + 5 * 0x10):
317 SyncLightSpecular0(5);
318 break;
319 case PICA_REG_INDEX_WORKAROUND(lighting.light[6].specular_0, 0x140 + 6 * 0x10):
320 SyncLightSpecular0(6);
321 break;
322 case PICA_REG_INDEX_WORKAROUND(lighting.light[7].specular_0, 0x140 + 7 * 0x10):
323 SyncLightSpecular0(7);
324 break;
325
326 // Fragment lighting specular 1 color
327 case PICA_REG_INDEX_WORKAROUND(lighting.light[0].specular_1, 0x141 + 0 * 0x10):
328 SyncLightSpecular1(0);
329 break;
330 case PICA_REG_INDEX_WORKAROUND(lighting.light[1].specular_1, 0x141 + 1 * 0x10):
331 SyncLightSpecular1(1);
332 break;
333 case PICA_REG_INDEX_WORKAROUND(lighting.light[2].specular_1, 0x141 + 2 * 0x10):
334 SyncLightSpecular1(2);
335 break;
336 case PICA_REG_INDEX_WORKAROUND(lighting.light[3].specular_1, 0x141 + 3 * 0x10):
337 SyncLightSpecular1(3);
338 break;
339 case PICA_REG_INDEX_WORKAROUND(lighting.light[4].specular_1, 0x141 + 4 * 0x10):
340 SyncLightSpecular1(4);
341 break;
342 case PICA_REG_INDEX_WORKAROUND(lighting.light[5].specular_1, 0x141 + 5 * 0x10):
343 SyncLightSpecular1(5);
344 break;
345 case PICA_REG_INDEX_WORKAROUND(lighting.light[6].specular_1, 0x141 + 6 * 0x10):
346 SyncLightSpecular1(6);
347 break;
348 case PICA_REG_INDEX_WORKAROUND(lighting.light[7].specular_1, 0x141 + 7 * 0x10):
349 SyncLightSpecular1(7);
350 break;
351
300 // Fragment lighting diffuse color 352 // Fragment lighting diffuse color
301 case PICA_REG_INDEX_WORKAROUND(lighting.light[0].diffuse, 0x142 + 0 * 0x10): 353 case PICA_REG_INDEX_WORKAROUND(lighting.light[0].diffuse, 0x142 + 0 * 0x10):
302 SyncLightDiffuse(0); 354 SyncLightDiffuse(0);
@@ -835,6 +887,22 @@ void RasterizerOpenGL::SyncLightingLUT(unsigned lut_index) {
835 } 887 }
836} 888}
837 889
890void RasterizerOpenGL::SyncLightSpecular0(int light_index) {
891 auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.light[light_index].specular_0);
892 if (color != uniform_block_data.data.light_src[light_index].specular_0) {
893 uniform_block_data.data.light_src[light_index].specular_0 = color;
894 uniform_block_data.dirty = true;
895 }
896}
897
898void RasterizerOpenGL::SyncLightSpecular1(int light_index) {
899 auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.light[light_index].specular_1);
900 if (color != uniform_block_data.data.light_src[light_index].specular_1) {
901 uniform_block_data.data.light_src[light_index].specular_1 = color;
902 uniform_block_data.dirty = true;
903 }
904}
905
838void RasterizerOpenGL::SyncLightDiffuse(int light_index) { 906void RasterizerOpenGL::SyncLightDiffuse(int light_index) {
839 auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.light[light_index].diffuse); 907 auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.light[light_index].diffuse);
840 if (color != uniform_block_data.data.light_src[light_index].diffuse) { 908 if (color != uniform_block_data.data.light_src[light_index].diffuse) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index ba0b05802..9e93b8b2f 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -87,6 +87,10 @@ struct PicaShaderConfig {
87 res.light_src[light_index].dist_atten_scale = Pica::float20::FromRawFloat20(light.dist_atten_scale).ToFloat32(); 87 res.light_src[light_index].dist_atten_scale = Pica::float20::FromRawFloat20(light.dist_atten_scale).ToFloat32();
88 } 88 }
89 89
90 res.lighting_lut.d0_abs = (regs.lighting.abs_lut_input.d0 == 0);
91 res.lighting_lut.d0_type = (Pica::Regs::LightingLutInput)regs.lighting.lut_input.d0.Value();
92 res.clamp_highlights = regs.lighting.light_env.clamp_highlights;
93
90 return res; 94 return res;
91 } 95 }
92 96
@@ -118,6 +122,12 @@ struct PicaShaderConfig {
118 122
119 bool lighting_enabled = false; 123 bool lighting_enabled = false;
120 unsigned num_lights = 0; 124 unsigned num_lights = 0;
125 bool clamp_highlights = false;
126
127 struct {
128 bool d0_abs = false;
129 Pica::Regs::LightingLutInput d0_type = Pica::Regs::LightingLutInput::NH;
130 } lighting_lut;
121 }; 131 };
122}; 132};
123 133
@@ -231,6 +241,10 @@ private:
231 }; 241 };
232 242
233 struct LightSrc { 243 struct LightSrc {
244 std::array<GLfloat, 3> specular_0;
245 INSERT_PADDING_WORDS(1);
246 std::array<GLfloat, 3> specular_1;
247 INSERT_PADDING_WORDS(1);
234 std::array<GLfloat, 3> diffuse; 248 std::array<GLfloat, 3> diffuse;
235 INSERT_PADDING_WORDS(1); 249 INSERT_PADDING_WORDS(1);
236 std::array<GLfloat, 3> ambient; 250 std::array<GLfloat, 3> ambient;
@@ -316,6 +330,12 @@ private:
316 /// Syncs the specified light's position to match the PICA register 330 /// Syncs the specified light's position to match the PICA register
317 void SyncLightPosition(int light_index); 331 void SyncLightPosition(int light_index);
318 332
333 /// Syncs the specified light's specular 0 color to match the PICA register
334 void SyncLightSpecular0(int light_index);
335
336 /// Syncs the specified light's specular 1 color to match the PICA register
337 void SyncLightSpecular1(int light_index);
338
319 /// Syncs the remaining OpenGL drawing state to match the current PICA state 339 /// Syncs the remaining OpenGL drawing state to match the current PICA state
320 void SyncDrawState(); 340 void SyncDrawState();
321 341
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index cf99cff76..abcc89f1d 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -35,8 +35,7 @@ static void AppendSource(std::string& out, TevStageConfig::Source source,
35 out += "primary_fragment_color"; 35 out += "primary_fragment_color";
36 break; 36 break;
37 case Source::SecondaryFragmentColor: 37 case Source::SecondaryFragmentColor:
38 // HACK: Until we implement fragment lighting, use zero 38 out += "secondary_fragment_color";
39 out += "vec4(0.0)";
40 break; 39 break;
41 case Source::Texture0: 40 case Source::Texture0:
42 out += "texture(tex[0], texcoord[0])"; 41 out += "texture(tex[0], texcoord[0])";
@@ -334,6 +333,8 @@ in vec3 view;
334out vec4 color; 333out vec4 color;
335 334
336struct LightSrc { 335struct LightSrc {
336 vec3 specular_0;
337 vec3 specular_1;
337 vec3 diffuse; 338 vec3 diffuse;
338 vec3 ambient; 339 vec3 ambient;
339 vec3 position; 340 vec3 position;
@@ -358,6 +359,7 @@ uniform sampler2D tex[3];
358 359
359void main() { 360void main() {
360vec4 primary_fragment_color = vec4(0.0); 361vec4 primary_fragment_color = vec4(0.0);
362vec4 secondary_fragment_color = vec4(0.0);
361)"; 363)";
362 364
363 if (config.lighting_enabled) { 365 if (config.lighting_enabled) {
@@ -367,41 +369,97 @@ vec4 primary_fragment_color = vec4(0.0);
367 out += " 1.f - 2.f*(normquat.x*normquat.x + normquat.y*normquat.y)));\n"; 369 out += " 1.f - 2.f*(normquat.x*normquat.x + normquat.y*normquat.y)));\n";
368 out += "vec4 secondary_color = vec4(0.0);\n"; 370 out += "vec4 secondary_color = vec4(0.0);\n";
369 out += "vec3 diffuse_sum = vec3(0.0);\n"; 371 out += "vec3 diffuse_sum = vec3(0.0);\n";
372 out += "vec3 specular_sum = vec3(0.0);\n";
370 out += "vec3 fragment_position = -view;\n"; 373 out += "vec3 fragment_position = -view;\n";
374 out += "vec3 light_vector = vec3(0.0);\n";
375 out += "float dist_atten = 1.0;\n";
376
377 // Gets the index into the specified lookup table for specular lighting
378 auto GetLutIndex = [&](unsigned light_num, Regs::LightingLutInput input, bool abs) {
379 const std::string half_angle = "normalize(view + light_vector)";
380 std::string index;
381 switch (input) {
382 case Regs::LightingLutInput::NH:
383 index = "dot(normal, " + half_angle + ")";
384 break;
385
386 case Regs::LightingLutInput::VH:
387 index = std::string("dot(view, " + half_angle + ")");
388 break;
389
390 case Regs::LightingLutInput::NV:
391 index = std::string("dot(normal, view)");
392 break;
393
394 case Regs::LightingLutInput::LN:
395 index = std::string("dot(light_vector, normal)");
396 break;
397
398 default:
399 LOG_CRITICAL(HW_GPU, "Unknown lighting LUT input %d\n", (int)input);
400 UNIMPLEMENTED();
401 break;
402 }
403
404 if (abs) {
405 // In the range of [ 0.f, 1.f]
406 index = config.light_src[light_num].two_sided_diffuse ? "abs(" + index + ")" : "max(" + index + ", 0.f)";
407 return "clamp(int(" + index + " * 256.0), 0, 255)";
408 } else {
409 // In the range of [-1.f, 1.f]
410 index = "clamp(" + index + ", -1.0, 1.0)";
411 return std::string("uint(int(" + index + " * 127.f) & 0xff)");
412 }
413
414 return std::string();
415 };
371 416
372 for (unsigned light_index = 0; light_index < config.num_lights; ++light_index) { 417 for (unsigned light_index = 0; light_index < config.num_lights; ++light_index) {
373 unsigned num = config.light_src[light_index].num; 418 unsigned num = config.light_src[light_index].num;
374 std::string light_src = "light_src[" + std::to_string(num) + "]"; 419 std::string light_src = "light_src[" + std::to_string(num) + "]";
375 420
376 std::string light_vector;
377 if (config.light_src[light_index].directional) 421 if (config.light_src[light_index].directional)
378 light_vector = "normalize(-" + light_src + ".position)"; 422 out += "light_vector = normalize(-" + light_src + ".position);\n";
379 else 423 else
380 light_vector = "normalize(" + light_src + ".position - fragment_position)"; 424 out += "light_vector = normalize(" + light_src + ".position - fragment_position);\n";
381 425
382 std::string dot_product; 426 std::string dot_product;
383 if (config.light_src[light_index].two_sided_diffuse) 427 if (config.light_src[light_index].two_sided_diffuse)
384 dot_product = "abs(dot(" + light_vector + ", normal))"; 428 dot_product = "abs(dot(light_vector, normal))";
385 else 429 else
386 dot_product = "max(dot(" + light_vector + ", normal), 0.0)"; 430 dot_product = "max(dot(light_vector, normal), 0.0)";
387 431
388 std::string dist_atten = "1.0"; 432 // Compute distance attenuation value
433 out += "dist_atten = 1.0;\n";
389 if (config.light_src[light_index].dist_atten_enabled) { 434 if (config.light_src[light_index].dist_atten_enabled) {
390 std::string scale = std::to_string(config.light_src[light_index].dist_atten_scale); 435 std::string scale = std::to_string(config.light_src[light_index].dist_atten_scale);
391 std::string bias = std::to_string(config.light_src[light_index].dist_atten_bias); 436 std::string bias = std::to_string(config.light_src[light_index].dist_atten_bias);
392 std::string lut_index = "(" + scale + " * length(fragment_position - " + light_src + ".position) + " + bias + ")"; 437 std::string lut_index = "(" + scale + " * length(fragment_position - " + light_src + ".position) + " + bias + ")";
393 std::string clamped_lut_index = "((clamp(int(" + lut_index + " * 256.0), 0, 255)))"; 438 std::string clamped_lut_index = "((clamp(int(" + lut_index + " * 256.0), 0, 255)))";
394 439
395 unsigned lut_num = ((unsigned)Regs::LightingSampler::DistanceAttenuation + num); 440 const unsigned lut_num = ((unsigned)Regs::LightingSampler::DistanceAttenuation + num);
396 441 out += "dist_atten = lighting_lut_" + std::to_string(lut_num / 4) + "[" + clamped_lut_index + "][" + std::to_string(lut_num & 3) + "];\n";
397 dist_atten = "lighting_lut_" + std::to_string(lut_num /4) + "[" + clamped_lut_index + "][" + std::to_string(lut_num & 3) + "]";
398 } 442 }
399 443
400 out += "diffuse_sum += ((light_src[" + std::to_string(num) + "].diffuse * " + dot_product + ") + light_src[" + std::to_string(num) + "].ambient) * " + dist_atten + ";\n"; 444 // Compute primary fragment color (diffuse lighting) function
445 out += "diffuse_sum += ((light_src[" + std::to_string(num) + "].diffuse * " + dot_product + ") + light_src[" + std::to_string(num) + "].ambient) * dist_atten;\n";
446
447 // 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);
449 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) + "]";
451
452 out += "specular_sum += (" + lut_lookup + " * light_src[" + std::to_string(num) + "].specular_0 * dist_atten);\n";
453 }
454
455 out += "float clamp_highlights = 1.0;\n";
456 if (config.clamp_highlights) {
457 out += "if (dot(light_vector, normal) <= 0.0) clamp_highlights = 0.0;\n";
401 } 458 }
402 459
403 out += "diffuse_sum += lighting_global_ambient;\n"; 460 out += "diffuse_sum += lighting_global_ambient;\n";
404 out += "primary_fragment_color = vec4(clamp(diffuse_sum, vec3(0.0), vec3(1.0)), 1.0);\n"; 461 out += "primary_fragment_color = vec4(clamp(diffuse_sum, vec3(0.0), vec3(1.0)), 1.0);\n";
462 out += "secondary_fragment_color = vec4(clamp(clamp_highlights * specular_sum, vec3(0.0), vec3(1.0)), 1.0);\n";
405 } 463 }
406 464
407 // Do not do any sort of processing if it's obvious we're not going to pass the alpha test 465 // Do not do any sort of processing if it's obvious we're not going to pass the alpha test