gl_rasterizer.cpp 68 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666
  1. // Copyright 2015 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <memory>
  5. #include <string>
  6. #include <tuple>
  7. #include <utility>
  8. #include <glad/glad.h>
  9. #include "common/assert.h"
  10. #include "common/color.h"
  11. #include "common/logging/log.h"
  12. #include "common/math_util.h"
  13. #include "common/microprofile.h"
  14. #include "common/vector_math.h"
  15. #include "core/hw/gpu.h"
  16. #include "video_core/pica_state.h"
  17. #include "video_core/regs_framebuffer.h"
  18. #include "video_core/regs_rasterizer.h"
  19. #include "video_core/regs_texturing.h"
  20. #include "video_core/renderer_opengl/gl_rasterizer.h"
  21. #include "video_core/renderer_opengl/gl_shader_gen.h"
  22. #include "video_core/renderer_opengl/pica_to_gl.h"
  23. #include "video_core/renderer_opengl/renderer_opengl.h"
  24. MICROPROFILE_DEFINE(OpenGL_Drawing, "OpenGL", "Drawing", MP_RGB(128, 128, 192));
  25. MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255));
  26. MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100));
  27. RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) {
  28. // Create sampler objects
  29. for (size_t i = 0; i < texture_samplers.size(); ++i) {
  30. texture_samplers[i].Create();
  31. state.texture_units[i].sampler = texture_samplers[i].sampler.handle;
  32. }
  33. // Generate VBO, VAO and UBO
  34. vertex_buffer.Create();
  35. vertex_array.Create();
  36. uniform_buffer.Create();
  37. state.draw.vertex_array = vertex_array.handle;
  38. state.draw.vertex_buffer = vertex_buffer.handle;
  39. state.draw.uniform_buffer = uniform_buffer.handle;
  40. state.Apply();
  41. // Bind the UBO to binding point 0
  42. glBindBufferBase(GL_UNIFORM_BUFFER, 0, uniform_buffer.handle);
  43. uniform_block_data.dirty = true;
  44. for (unsigned index = 0; index < lighting_luts.size(); index++) {
  45. uniform_block_data.lut_dirty[index] = true;
  46. }
  47. uniform_block_data.fog_lut_dirty = true;
  48. uniform_block_data.proctex_noise_lut_dirty = true;
  49. uniform_block_data.proctex_color_map_dirty = true;
  50. uniform_block_data.proctex_alpha_map_dirty = true;
  51. uniform_block_data.proctex_lut_dirty = true;
  52. uniform_block_data.proctex_diff_lut_dirty = true;
  53. // Set vertex attributes
  54. glVertexAttribPointer(GLShader::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE,
  55. sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position));
  56. glEnableVertexAttribArray(GLShader::ATTRIBUTE_POSITION);
  57. glVertexAttribPointer(GLShader::ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex),
  58. (GLvoid*)offsetof(HardwareVertex, color));
  59. glEnableVertexAttribArray(GLShader::ATTRIBUTE_COLOR);
  60. glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD0, 2, GL_FLOAT, GL_FALSE,
  61. sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0));
  62. glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD1, 2, GL_FLOAT, GL_FALSE,
  63. sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1));
  64. glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD2, 2, GL_FLOAT, GL_FALSE,
  65. sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2));
  66. glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD0);
  67. glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD1);
  68. glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD2);
  69. glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD0_W, 1, GL_FLOAT, GL_FALSE,
  70. sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0_w));
  71. glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD0_W);
  72. glVertexAttribPointer(GLShader::ATTRIBUTE_NORMQUAT, 4, GL_FLOAT, GL_FALSE,
  73. sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, normquat));
  74. glEnableVertexAttribArray(GLShader::ATTRIBUTE_NORMQUAT);
  75. glVertexAttribPointer(GLShader::ATTRIBUTE_VIEW, 3, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex),
  76. (GLvoid*)offsetof(HardwareVertex, view));
  77. glEnableVertexAttribArray(GLShader::ATTRIBUTE_VIEW);
  78. // Create render framebuffer
  79. framebuffer.Create();
  80. // Allocate and bind lighting lut textures
  81. for (size_t i = 0; i < lighting_luts.size(); ++i) {
  82. lighting_luts[i].Create();
  83. state.lighting_luts[i].texture_1d = lighting_luts[i].handle;
  84. }
  85. state.Apply();
  86. for (size_t i = 0; i < lighting_luts.size(); ++i) {
  87. glActiveTexture(static_cast<GLenum>(GL_TEXTURE3 + i));
  88. glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, 256, 0, GL_RGBA, GL_FLOAT, nullptr);
  89. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  90. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  91. }
  92. // Setup the LUT for the fog
  93. {
  94. fog_lut.Create();
  95. state.fog_lut.texture_1d = fog_lut.handle;
  96. }
  97. state.Apply();
  98. glActiveTexture(GL_TEXTURE9);
  99. glTexImage1D(GL_TEXTURE_1D, 0, GL_R32UI, 128, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, nullptr);
  100. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  101. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  102. // Setup the noise LUT for proctex
  103. proctex_noise_lut.Create();
  104. state.proctex_noise_lut.texture_1d = proctex_noise_lut.handle;
  105. state.Apply();
  106. glActiveTexture(GL_TEXTURE10);
  107. glTexImage1D(GL_TEXTURE_1D, 0, GL_RG32F, 128, 0, GL_RG, GL_FLOAT, nullptr);
  108. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  109. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  110. // Setup the color map for proctex
  111. proctex_color_map.Create();
  112. state.proctex_color_map.texture_1d = proctex_color_map.handle;
  113. state.Apply();
  114. glActiveTexture(GL_TEXTURE11);
  115. glTexImage1D(GL_TEXTURE_1D, 0, GL_RG32F, 128, 0, GL_RG, GL_FLOAT, nullptr);
  116. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  117. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  118. // Setup the alpha map for proctex
  119. proctex_alpha_map.Create();
  120. state.proctex_alpha_map.texture_1d = proctex_alpha_map.handle;
  121. state.Apply();
  122. glActiveTexture(GL_TEXTURE12);
  123. glTexImage1D(GL_TEXTURE_1D, 0, GL_RG32F, 128, 0, GL_RG, GL_FLOAT, nullptr);
  124. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  125. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  126. // Setup the LUT for proctex
  127. proctex_lut.Create();
  128. state.proctex_lut.texture_1d = proctex_lut.handle;
  129. state.Apply();
  130. glActiveTexture(GL_TEXTURE13);
  131. glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, 256, 0, GL_RGBA, GL_FLOAT, nullptr);
  132. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  133. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  134. // Setup the difference LUT for proctex
  135. proctex_diff_lut.Create();
  136. state.proctex_diff_lut.texture_1d = proctex_diff_lut.handle;
  137. state.Apply();
  138. glActiveTexture(GL_TEXTURE14);
  139. glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, 256, 0, GL_RGBA, GL_FLOAT, nullptr);
  140. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  141. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  142. // Sync fixed function OpenGL state
  143. SyncCullMode();
  144. SyncBlendEnabled();
  145. SyncBlendFuncs();
  146. SyncBlendColor();
  147. SyncLogicOp();
  148. SyncStencilTest();
  149. SyncDepthTest();
  150. SyncColorWriteMask();
  151. SyncStencilWriteMask();
  152. SyncDepthWriteMask();
  153. }
  154. RasterizerOpenGL::~RasterizerOpenGL() {}
  155. /**
  156. * This is a helper function to resolve an issue when interpolating opposite quaternions. See below
  157. * for a detailed description of this issue (yuriks):
  158. *
  159. * For any rotation, there are two quaternions Q, and -Q, that represent the same rotation. If you
  160. * interpolate two quaternions that are opposite, instead of going from one rotation to another
  161. * using the shortest path, you'll go around the longest path. You can test if two quaternions are
  162. * opposite by checking if Dot(Q1, Q2) < 0. In that case, you can flip either of them, therefore
  163. * making Dot(Q1, -Q2) positive.
  164. *
  165. * This solution corrects this issue per-vertex before passing the quaternions to OpenGL. This is
  166. * correct for most cases but can still rotate around the long way sometimes. An implementation
  167. * which did `lerp(lerp(Q1, Q2), Q3)` (with proper weighting), applying the dot product check
  168. * between each step would work for those cases at the cost of being more complex to implement.
  169. *
  170. * Fortunately however, the 3DS hardware happens to also use this exact same logic to work around
  171. * these issues, making this basic implementation actually more accurate to the hardware.
  172. */
  173. static bool AreQuaternionsOpposite(Math::Vec4<Pica::float24> qa, Math::Vec4<Pica::float24> qb) {
  174. Math::Vec4f a{qa.x.ToFloat32(), qa.y.ToFloat32(), qa.z.ToFloat32(), qa.w.ToFloat32()};
  175. Math::Vec4f b{qb.x.ToFloat32(), qb.y.ToFloat32(), qb.z.ToFloat32(), qb.w.ToFloat32()};
  176. return (Math::Dot(a, b) < 0.f);
  177. }
  178. void RasterizerOpenGL::AddTriangle(const Pica::Shader::OutputVertex& v0,
  179. const Pica::Shader::OutputVertex& v1,
  180. const Pica::Shader::OutputVertex& v2) {
  181. vertex_batch.emplace_back(v0, false);
  182. vertex_batch.emplace_back(v1, AreQuaternionsOpposite(v0.quat, v1.quat));
  183. vertex_batch.emplace_back(v2, AreQuaternionsOpposite(v0.quat, v2.quat));
  184. }
  185. void RasterizerOpenGL::DrawTriangles() {
  186. if (vertex_batch.empty())
  187. return;
  188. MICROPROFILE_SCOPE(OpenGL_Drawing);
  189. const auto& regs = Pica::g_state.regs;
  190. // Sync and bind the framebuffer surfaces
  191. CachedSurface* color_surface;
  192. CachedSurface* depth_surface;
  193. MathUtil::Rectangle<int> rect;
  194. std::tie(color_surface, depth_surface, rect) =
  195. res_cache.GetFramebufferSurfaces(regs.framebuffer.framebuffer);
  196. state.draw.draw_framebuffer = framebuffer.handle;
  197. state.Apply();
  198. glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
  199. color_surface != nullptr ? color_surface->texture.handle : 0, 0);
  200. glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
  201. depth_surface != nullptr ? depth_surface->texture.handle : 0, 0);
  202. bool has_stencil =
  203. regs.framebuffer.framebuffer.depth_format == Pica::FramebufferRegs::DepthFormat::D24S8;
  204. glFramebufferTexture2D(
  205. GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
  206. (has_stencil && depth_surface != nullptr) ? depth_surface->texture.handle : 0, 0);
  207. // Sync the viewport
  208. // These registers hold half-width and half-height, so must be multiplied by 2
  209. GLsizei viewport_width =
  210. (GLsizei)Pica::float24::FromRaw(regs.rasterizer.viewport_size_x).ToFloat32() * 2;
  211. GLsizei viewport_height =
  212. (GLsizei)Pica::float24::FromRaw(regs.rasterizer.viewport_size_y).ToFloat32() * 2;
  213. glViewport(
  214. (GLint)(rect.left + regs.rasterizer.viewport_corner.x * color_surface->res_scale_width),
  215. (GLint)(rect.bottom + regs.rasterizer.viewport_corner.y * color_surface->res_scale_height),
  216. (GLsizei)(viewport_width * color_surface->res_scale_width),
  217. (GLsizei)(viewport_height * color_surface->res_scale_height));
  218. if (uniform_block_data.data.framebuffer_scale[0] != color_surface->res_scale_width ||
  219. uniform_block_data.data.framebuffer_scale[1] != color_surface->res_scale_height) {
  220. uniform_block_data.data.framebuffer_scale[0] = color_surface->res_scale_width;
  221. uniform_block_data.data.framebuffer_scale[1] = color_surface->res_scale_height;
  222. uniform_block_data.dirty = true;
  223. }
  224. // Scissor checks are window-, not viewport-relative, which means that if the cached texture
  225. // sub-rect changes, the scissor bounds also need to be updated.
  226. GLint scissor_x1 = static_cast<GLint>(
  227. rect.left + regs.rasterizer.scissor_test.x1 * color_surface->res_scale_width);
  228. GLint scissor_y1 = static_cast<GLint>(
  229. rect.bottom + regs.rasterizer.scissor_test.y1 * color_surface->res_scale_height);
  230. // x2, y2 have +1 added to cover the entire pixel area, otherwise you might get cracks when
  231. // scaling or doing multisampling.
  232. GLint scissor_x2 = static_cast<GLint>(
  233. rect.left + (regs.rasterizer.scissor_test.x2 + 1) * color_surface->res_scale_width);
  234. GLint scissor_y2 = static_cast<GLint>(
  235. rect.bottom + (regs.rasterizer.scissor_test.y2 + 1) * color_surface->res_scale_height);
  236. if (uniform_block_data.data.scissor_x1 != scissor_x1 ||
  237. uniform_block_data.data.scissor_x2 != scissor_x2 ||
  238. uniform_block_data.data.scissor_y1 != scissor_y1 ||
  239. uniform_block_data.data.scissor_y2 != scissor_y2) {
  240. uniform_block_data.data.scissor_x1 = scissor_x1;
  241. uniform_block_data.data.scissor_x2 = scissor_x2;
  242. uniform_block_data.data.scissor_y1 = scissor_y1;
  243. uniform_block_data.data.scissor_y2 = scissor_y2;
  244. uniform_block_data.dirty = true;
  245. }
  246. // Sync and bind the texture surfaces
  247. const auto pica_textures = regs.texturing.GetTextures();
  248. for (unsigned texture_index = 0; texture_index < pica_textures.size(); ++texture_index) {
  249. const auto& texture = pica_textures[texture_index];
  250. if (texture.enabled) {
  251. texture_samplers[texture_index].SyncWithConfig(texture.config);
  252. CachedSurface* surface = res_cache.GetTextureSurface(texture);
  253. if (surface != nullptr) {
  254. state.texture_units[texture_index].texture_2d = surface->texture.handle;
  255. } else {
  256. // Can occur when texture addr is null or its memory is unmapped/invalid
  257. state.texture_units[texture_index].texture_2d = 0;
  258. }
  259. } else {
  260. state.texture_units[texture_index].texture_2d = 0;
  261. }
  262. }
  263. // Sync and bind the shader
  264. if (shader_dirty) {
  265. SetShader();
  266. shader_dirty = false;
  267. }
  268. // Sync the lighting luts
  269. for (unsigned index = 0; index < lighting_luts.size(); index++) {
  270. if (uniform_block_data.lut_dirty[index]) {
  271. SyncLightingLUT(index);
  272. uniform_block_data.lut_dirty[index] = false;
  273. }
  274. }
  275. // Sync the fog lut
  276. if (uniform_block_data.fog_lut_dirty) {
  277. SyncFogLUT();
  278. uniform_block_data.fog_lut_dirty = false;
  279. }
  280. // Sync the proctex noise lut
  281. if (uniform_block_data.proctex_noise_lut_dirty) {
  282. SyncProcTexNoiseLUT();
  283. uniform_block_data.proctex_noise_lut_dirty = false;
  284. }
  285. // Sync the proctex color map
  286. if (uniform_block_data.proctex_color_map_dirty) {
  287. SyncProcTexColorMap();
  288. uniform_block_data.proctex_color_map_dirty = false;
  289. }
  290. // Sync the proctex alpha map
  291. if (uniform_block_data.proctex_alpha_map_dirty) {
  292. SyncProcTexAlphaMap();
  293. uniform_block_data.proctex_alpha_map_dirty = false;
  294. }
  295. // Sync the proctex lut
  296. if (uniform_block_data.proctex_lut_dirty) {
  297. SyncProcTexLUT();
  298. uniform_block_data.proctex_lut_dirty = false;
  299. }
  300. // Sync the proctex difference lut
  301. if (uniform_block_data.proctex_diff_lut_dirty) {
  302. SyncProcTexDiffLUT();
  303. uniform_block_data.proctex_diff_lut_dirty = false;
  304. }
  305. // Sync the uniform data
  306. if (uniform_block_data.dirty) {
  307. glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformData), &uniform_block_data.data,
  308. GL_STATIC_DRAW);
  309. uniform_block_data.dirty = false;
  310. }
  311. state.Apply();
  312. // Draw the vertex batch
  313. glBufferData(GL_ARRAY_BUFFER, vertex_batch.size() * sizeof(HardwareVertex), vertex_batch.data(),
  314. GL_STREAM_DRAW);
  315. glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertex_batch.size());
  316. // Mark framebuffer surfaces as dirty
  317. // TODO: Restrict invalidation area to the viewport
  318. if (color_surface != nullptr) {
  319. color_surface->dirty = true;
  320. res_cache.FlushRegion(color_surface->addr, color_surface->size, color_surface, true);
  321. }
  322. if (depth_surface != nullptr) {
  323. depth_surface->dirty = true;
  324. res_cache.FlushRegion(depth_surface->addr, depth_surface->size, depth_surface, true);
  325. }
  326. vertex_batch.clear();
  327. // Unbind textures for potential future use as framebuffer attachments
  328. for (unsigned texture_index = 0; texture_index < pica_textures.size(); ++texture_index) {
  329. state.texture_units[texture_index].texture_2d = 0;
  330. }
  331. state.Apply();
  332. }
  333. void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
  334. const auto& regs = Pica::g_state.regs;
  335. switch (id) {
  336. // Culling
  337. case PICA_REG_INDEX(rasterizer.cull_mode):
  338. SyncCullMode();
  339. break;
  340. // Depth modifiers
  341. case PICA_REG_INDEX(rasterizer.viewport_depth_range):
  342. SyncDepthScale();
  343. break;
  344. case PICA_REG_INDEX(rasterizer.viewport_depth_near_plane):
  345. SyncDepthOffset();
  346. break;
  347. // Depth buffering
  348. case PICA_REG_INDEX(rasterizer.depthmap_enable):
  349. shader_dirty = true;
  350. break;
  351. // Blending
  352. case PICA_REG_INDEX(framebuffer.output_merger.alphablend_enable):
  353. SyncBlendEnabled();
  354. break;
  355. case PICA_REG_INDEX(framebuffer.output_merger.alpha_blending):
  356. SyncBlendFuncs();
  357. break;
  358. case PICA_REG_INDEX(framebuffer.output_merger.blend_const):
  359. SyncBlendColor();
  360. break;
  361. // Fog state
  362. case PICA_REG_INDEX(texturing.fog_color):
  363. SyncFogColor();
  364. break;
  365. case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[0], 0xe8):
  366. case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[1], 0xe9):
  367. case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[2], 0xea):
  368. case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[3], 0xeb):
  369. case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[4], 0xec):
  370. case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[5], 0xed):
  371. case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[6], 0xee):
  372. case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[7], 0xef):
  373. uniform_block_data.fog_lut_dirty = true;
  374. break;
  375. // ProcTex state
  376. case PICA_REG_INDEX(texturing.proctex):
  377. case PICA_REG_INDEX(texturing.proctex_lut):
  378. case PICA_REG_INDEX(texturing.proctex_lut_offset):
  379. shader_dirty = true;
  380. break;
  381. case PICA_REG_INDEX(texturing.proctex_noise_u):
  382. case PICA_REG_INDEX(texturing.proctex_noise_v):
  383. case PICA_REG_INDEX(texturing.proctex_noise_frequency):
  384. SyncProcTexNoise();
  385. break;
  386. case PICA_REG_INDEX_WORKAROUND(texturing.proctex_lut_data[0], 0xb0):
  387. case PICA_REG_INDEX_WORKAROUND(texturing.proctex_lut_data[1], 0xb1):
  388. case PICA_REG_INDEX_WORKAROUND(texturing.proctex_lut_data[2], 0xb2):
  389. case PICA_REG_INDEX_WORKAROUND(texturing.proctex_lut_data[3], 0xb3):
  390. case PICA_REG_INDEX_WORKAROUND(texturing.proctex_lut_data[4], 0xb4):
  391. case PICA_REG_INDEX_WORKAROUND(texturing.proctex_lut_data[5], 0xb5):
  392. case PICA_REG_INDEX_WORKAROUND(texturing.proctex_lut_data[6], 0xb6):
  393. case PICA_REG_INDEX_WORKAROUND(texturing.proctex_lut_data[7], 0xb7):
  394. using Pica::TexturingRegs;
  395. switch (regs.texturing.proctex_lut_config.ref_table.Value()) {
  396. case TexturingRegs::ProcTexLutTable::Noise:
  397. uniform_block_data.proctex_noise_lut_dirty = true;
  398. break;
  399. case TexturingRegs::ProcTexLutTable::ColorMap:
  400. uniform_block_data.proctex_color_map_dirty = true;
  401. break;
  402. case TexturingRegs::ProcTexLutTable::AlphaMap:
  403. uniform_block_data.proctex_alpha_map_dirty = true;
  404. break;
  405. case TexturingRegs::ProcTexLutTable::Color:
  406. uniform_block_data.proctex_lut_dirty = true;
  407. break;
  408. case TexturingRegs::ProcTexLutTable::ColorDiff:
  409. uniform_block_data.proctex_diff_lut_dirty = true;
  410. break;
  411. }
  412. break;
  413. // Alpha test
  414. case PICA_REG_INDEX(framebuffer.output_merger.alpha_test):
  415. SyncAlphaTest();
  416. shader_dirty = true;
  417. break;
  418. // Sync GL stencil test + stencil write mask
  419. // (Pica stencil test function register also contains a stencil write mask)
  420. case PICA_REG_INDEX(framebuffer.output_merger.stencil_test.raw_func):
  421. SyncStencilTest();
  422. SyncStencilWriteMask();
  423. break;
  424. case PICA_REG_INDEX(framebuffer.output_merger.stencil_test.raw_op):
  425. case PICA_REG_INDEX(framebuffer.framebuffer.depth_format):
  426. SyncStencilTest();
  427. break;
  428. // Sync GL depth test + depth and color write mask
  429. // (Pica depth test function register also contains a depth and color write mask)
  430. case PICA_REG_INDEX(framebuffer.output_merger.depth_test_enable):
  431. SyncDepthTest();
  432. SyncDepthWriteMask();
  433. SyncColorWriteMask();
  434. break;
  435. // Sync GL depth and stencil write mask
  436. // (This is a dedicated combined depth / stencil write-enable register)
  437. case PICA_REG_INDEX(framebuffer.framebuffer.allow_depth_stencil_write):
  438. SyncDepthWriteMask();
  439. SyncStencilWriteMask();
  440. break;
  441. // Sync GL color write mask
  442. // (This is a dedicated color write-enable register)
  443. case PICA_REG_INDEX(framebuffer.framebuffer.allow_color_write):
  444. SyncColorWriteMask();
  445. break;
  446. // Scissor test
  447. case PICA_REG_INDEX(rasterizer.scissor_test.mode):
  448. shader_dirty = true;
  449. break;
  450. // Logic op
  451. case PICA_REG_INDEX(framebuffer.output_merger.logic_op):
  452. SyncLogicOp();
  453. break;
  454. case PICA_REG_INDEX(texturing.main_config):
  455. shader_dirty = true;
  456. break;
  457. // Texture 0 type
  458. case PICA_REG_INDEX(texturing.texture0.type):
  459. shader_dirty = true;
  460. break;
  461. // TEV stages
  462. // (This also syncs fog_mode and fog_flip which are part of tev_combiner_buffer_input)
  463. case PICA_REG_INDEX(texturing.tev_stage0.color_source1):
  464. case PICA_REG_INDEX(texturing.tev_stage0.color_modifier1):
  465. case PICA_REG_INDEX(texturing.tev_stage0.color_op):
  466. case PICA_REG_INDEX(texturing.tev_stage0.color_scale):
  467. case PICA_REG_INDEX(texturing.tev_stage1.color_source1):
  468. case PICA_REG_INDEX(texturing.tev_stage1.color_modifier1):
  469. case PICA_REG_INDEX(texturing.tev_stage1.color_op):
  470. case PICA_REG_INDEX(texturing.tev_stage1.color_scale):
  471. case PICA_REG_INDEX(texturing.tev_stage2.color_source1):
  472. case PICA_REG_INDEX(texturing.tev_stage2.color_modifier1):
  473. case PICA_REG_INDEX(texturing.tev_stage2.color_op):
  474. case PICA_REG_INDEX(texturing.tev_stage2.color_scale):
  475. case PICA_REG_INDEX(texturing.tev_stage3.color_source1):
  476. case PICA_REG_INDEX(texturing.tev_stage3.color_modifier1):
  477. case PICA_REG_INDEX(texturing.tev_stage3.color_op):
  478. case PICA_REG_INDEX(texturing.tev_stage3.color_scale):
  479. case PICA_REG_INDEX(texturing.tev_stage4.color_source1):
  480. case PICA_REG_INDEX(texturing.tev_stage4.color_modifier1):
  481. case PICA_REG_INDEX(texturing.tev_stage4.color_op):
  482. case PICA_REG_INDEX(texturing.tev_stage4.color_scale):
  483. case PICA_REG_INDEX(texturing.tev_stage5.color_source1):
  484. case PICA_REG_INDEX(texturing.tev_stage5.color_modifier1):
  485. case PICA_REG_INDEX(texturing.tev_stage5.color_op):
  486. case PICA_REG_INDEX(texturing.tev_stage5.color_scale):
  487. case PICA_REG_INDEX(texturing.tev_combiner_buffer_input):
  488. shader_dirty = true;
  489. break;
  490. case PICA_REG_INDEX(texturing.tev_stage0.const_r):
  491. SyncTevConstColor(0, regs.texturing.tev_stage0);
  492. break;
  493. case PICA_REG_INDEX(texturing.tev_stage1.const_r):
  494. SyncTevConstColor(1, regs.texturing.tev_stage1);
  495. break;
  496. case PICA_REG_INDEX(texturing.tev_stage2.const_r):
  497. SyncTevConstColor(2, regs.texturing.tev_stage2);
  498. break;
  499. case PICA_REG_INDEX(texturing.tev_stage3.const_r):
  500. SyncTevConstColor(3, regs.texturing.tev_stage3);
  501. break;
  502. case PICA_REG_INDEX(texturing.tev_stage4.const_r):
  503. SyncTevConstColor(4, regs.texturing.tev_stage4);
  504. break;
  505. case PICA_REG_INDEX(texturing.tev_stage5.const_r):
  506. SyncTevConstColor(5, regs.texturing.tev_stage5);
  507. break;
  508. // TEV combiner buffer color
  509. case PICA_REG_INDEX(texturing.tev_combiner_buffer_color):
  510. SyncCombinerColor();
  511. break;
  512. // Fragment lighting switches
  513. case PICA_REG_INDEX(lighting.disable):
  514. case PICA_REG_INDEX(lighting.max_light_index):
  515. case PICA_REG_INDEX(lighting.config0):
  516. case PICA_REG_INDEX(lighting.config1):
  517. case PICA_REG_INDEX(lighting.abs_lut_input):
  518. case PICA_REG_INDEX(lighting.lut_input):
  519. case PICA_REG_INDEX(lighting.lut_scale):
  520. case PICA_REG_INDEX(lighting.light_enable):
  521. break;
  522. // Fragment lighting specular 0 color
  523. case PICA_REG_INDEX_WORKAROUND(lighting.light[0].specular_0, 0x140 + 0 * 0x10):
  524. SyncLightSpecular0(0);
  525. break;
  526. case PICA_REG_INDEX_WORKAROUND(lighting.light[1].specular_0, 0x140 + 1 * 0x10):
  527. SyncLightSpecular0(1);
  528. break;
  529. case PICA_REG_INDEX_WORKAROUND(lighting.light[2].specular_0, 0x140 + 2 * 0x10):
  530. SyncLightSpecular0(2);
  531. break;
  532. case PICA_REG_INDEX_WORKAROUND(lighting.light[3].specular_0, 0x140 + 3 * 0x10):
  533. SyncLightSpecular0(3);
  534. break;
  535. case PICA_REG_INDEX_WORKAROUND(lighting.light[4].specular_0, 0x140 + 4 * 0x10):
  536. SyncLightSpecular0(4);
  537. break;
  538. case PICA_REG_INDEX_WORKAROUND(lighting.light[5].specular_0, 0x140 + 5 * 0x10):
  539. SyncLightSpecular0(5);
  540. break;
  541. case PICA_REG_INDEX_WORKAROUND(lighting.light[6].specular_0, 0x140 + 6 * 0x10):
  542. SyncLightSpecular0(6);
  543. break;
  544. case PICA_REG_INDEX_WORKAROUND(lighting.light[7].specular_0, 0x140 + 7 * 0x10):
  545. SyncLightSpecular0(7);
  546. break;
  547. // Fragment lighting specular 1 color
  548. case PICA_REG_INDEX_WORKAROUND(lighting.light[0].specular_1, 0x141 + 0 * 0x10):
  549. SyncLightSpecular1(0);
  550. break;
  551. case PICA_REG_INDEX_WORKAROUND(lighting.light[1].specular_1, 0x141 + 1 * 0x10):
  552. SyncLightSpecular1(1);
  553. break;
  554. case PICA_REG_INDEX_WORKAROUND(lighting.light[2].specular_1, 0x141 + 2 * 0x10):
  555. SyncLightSpecular1(2);
  556. break;
  557. case PICA_REG_INDEX_WORKAROUND(lighting.light[3].specular_1, 0x141 + 3 * 0x10):
  558. SyncLightSpecular1(3);
  559. break;
  560. case PICA_REG_INDEX_WORKAROUND(lighting.light[4].specular_1, 0x141 + 4 * 0x10):
  561. SyncLightSpecular1(4);
  562. break;
  563. case PICA_REG_INDEX_WORKAROUND(lighting.light[5].specular_1, 0x141 + 5 * 0x10):
  564. SyncLightSpecular1(5);
  565. break;
  566. case PICA_REG_INDEX_WORKAROUND(lighting.light[6].specular_1, 0x141 + 6 * 0x10):
  567. SyncLightSpecular1(6);
  568. break;
  569. case PICA_REG_INDEX_WORKAROUND(lighting.light[7].specular_1, 0x141 + 7 * 0x10):
  570. SyncLightSpecular1(7);
  571. break;
  572. // Fragment lighting diffuse color
  573. case PICA_REG_INDEX_WORKAROUND(lighting.light[0].diffuse, 0x142 + 0 * 0x10):
  574. SyncLightDiffuse(0);
  575. break;
  576. case PICA_REG_INDEX_WORKAROUND(lighting.light[1].diffuse, 0x142 + 1 * 0x10):
  577. SyncLightDiffuse(1);
  578. break;
  579. case PICA_REG_INDEX_WORKAROUND(lighting.light[2].diffuse, 0x142 + 2 * 0x10):
  580. SyncLightDiffuse(2);
  581. break;
  582. case PICA_REG_INDEX_WORKAROUND(lighting.light[3].diffuse, 0x142 + 3 * 0x10):
  583. SyncLightDiffuse(3);
  584. break;
  585. case PICA_REG_INDEX_WORKAROUND(lighting.light[4].diffuse, 0x142 + 4 * 0x10):
  586. SyncLightDiffuse(4);
  587. break;
  588. case PICA_REG_INDEX_WORKAROUND(lighting.light[5].diffuse, 0x142 + 5 * 0x10):
  589. SyncLightDiffuse(5);
  590. break;
  591. case PICA_REG_INDEX_WORKAROUND(lighting.light[6].diffuse, 0x142 + 6 * 0x10):
  592. SyncLightDiffuse(6);
  593. break;
  594. case PICA_REG_INDEX_WORKAROUND(lighting.light[7].diffuse, 0x142 + 7 * 0x10):
  595. SyncLightDiffuse(7);
  596. break;
  597. // Fragment lighting ambient color
  598. case PICA_REG_INDEX_WORKAROUND(lighting.light[0].ambient, 0x143 + 0 * 0x10):
  599. SyncLightAmbient(0);
  600. break;
  601. case PICA_REG_INDEX_WORKAROUND(lighting.light[1].ambient, 0x143 + 1 * 0x10):
  602. SyncLightAmbient(1);
  603. break;
  604. case PICA_REG_INDEX_WORKAROUND(lighting.light[2].ambient, 0x143 + 2 * 0x10):
  605. SyncLightAmbient(2);
  606. break;
  607. case PICA_REG_INDEX_WORKAROUND(lighting.light[3].ambient, 0x143 + 3 * 0x10):
  608. SyncLightAmbient(3);
  609. break;
  610. case PICA_REG_INDEX_WORKAROUND(lighting.light[4].ambient, 0x143 + 4 * 0x10):
  611. SyncLightAmbient(4);
  612. break;
  613. case PICA_REG_INDEX_WORKAROUND(lighting.light[5].ambient, 0x143 + 5 * 0x10):
  614. SyncLightAmbient(5);
  615. break;
  616. case PICA_REG_INDEX_WORKAROUND(lighting.light[6].ambient, 0x143 + 6 * 0x10):
  617. SyncLightAmbient(6);
  618. break;
  619. case PICA_REG_INDEX_WORKAROUND(lighting.light[7].ambient, 0x143 + 7 * 0x10):
  620. SyncLightAmbient(7);
  621. break;
  622. // Fragment lighting position
  623. case PICA_REG_INDEX_WORKAROUND(lighting.light[0].x, 0x144 + 0 * 0x10):
  624. case PICA_REG_INDEX_WORKAROUND(lighting.light[0].z, 0x145 + 0 * 0x10):
  625. SyncLightPosition(0);
  626. break;
  627. case PICA_REG_INDEX_WORKAROUND(lighting.light[1].x, 0x144 + 1 * 0x10):
  628. case PICA_REG_INDEX_WORKAROUND(lighting.light[1].z, 0x145 + 1 * 0x10):
  629. SyncLightPosition(1);
  630. break;
  631. case PICA_REG_INDEX_WORKAROUND(lighting.light[2].x, 0x144 + 2 * 0x10):
  632. case PICA_REG_INDEX_WORKAROUND(lighting.light[2].z, 0x145 + 2 * 0x10):
  633. SyncLightPosition(2);
  634. break;
  635. case PICA_REG_INDEX_WORKAROUND(lighting.light[3].x, 0x144 + 3 * 0x10):
  636. case PICA_REG_INDEX_WORKAROUND(lighting.light[3].z, 0x145 + 3 * 0x10):
  637. SyncLightPosition(3);
  638. break;
  639. case PICA_REG_INDEX_WORKAROUND(lighting.light[4].x, 0x144 + 4 * 0x10):
  640. case PICA_REG_INDEX_WORKAROUND(lighting.light[4].z, 0x145 + 4 * 0x10):
  641. SyncLightPosition(4);
  642. break;
  643. case PICA_REG_INDEX_WORKAROUND(lighting.light[5].x, 0x144 + 5 * 0x10):
  644. case PICA_REG_INDEX_WORKAROUND(lighting.light[5].z, 0x145 + 5 * 0x10):
  645. SyncLightPosition(5);
  646. break;
  647. case PICA_REG_INDEX_WORKAROUND(lighting.light[6].x, 0x144 + 6 * 0x10):
  648. case PICA_REG_INDEX_WORKAROUND(lighting.light[6].z, 0x145 + 6 * 0x10):
  649. SyncLightPosition(6);
  650. break;
  651. case PICA_REG_INDEX_WORKAROUND(lighting.light[7].x, 0x144 + 7 * 0x10):
  652. case PICA_REG_INDEX_WORKAROUND(lighting.light[7].z, 0x145 + 7 * 0x10):
  653. SyncLightPosition(7);
  654. break;
  655. // Fragment spot lighting direction
  656. case PICA_REG_INDEX_WORKAROUND(lighting.light[0].spot_x, 0x146 + 0 * 0x10):
  657. case PICA_REG_INDEX_WORKAROUND(lighting.light[0].spot_z, 0x147 + 0 * 0x10):
  658. SyncLightSpotDirection(0);
  659. break;
  660. case PICA_REG_INDEX_WORKAROUND(lighting.light[1].spot_x, 0x146 + 1 * 0x10):
  661. case PICA_REG_INDEX_WORKAROUND(lighting.light[1].spot_z, 0x147 + 1 * 0x10):
  662. SyncLightSpotDirection(1);
  663. break;
  664. case PICA_REG_INDEX_WORKAROUND(lighting.light[2].spot_x, 0x146 + 2 * 0x10):
  665. case PICA_REG_INDEX_WORKAROUND(lighting.light[2].spot_z, 0x147 + 2 * 0x10):
  666. SyncLightSpotDirection(2);
  667. break;
  668. case PICA_REG_INDEX_WORKAROUND(lighting.light[3].spot_x, 0x146 + 3 * 0x10):
  669. case PICA_REG_INDEX_WORKAROUND(lighting.light[3].spot_z, 0x147 + 3 * 0x10):
  670. SyncLightSpotDirection(3);
  671. break;
  672. case PICA_REG_INDEX_WORKAROUND(lighting.light[4].spot_x, 0x146 + 4 * 0x10):
  673. case PICA_REG_INDEX_WORKAROUND(lighting.light[4].spot_z, 0x147 + 4 * 0x10):
  674. SyncLightSpotDirection(4);
  675. break;
  676. case PICA_REG_INDEX_WORKAROUND(lighting.light[5].spot_x, 0x146 + 5 * 0x10):
  677. case PICA_REG_INDEX_WORKAROUND(lighting.light[5].spot_z, 0x147 + 5 * 0x10):
  678. SyncLightSpotDirection(5);
  679. break;
  680. case PICA_REG_INDEX_WORKAROUND(lighting.light[6].spot_x, 0x146 + 6 * 0x10):
  681. case PICA_REG_INDEX_WORKAROUND(lighting.light[6].spot_z, 0x147 + 6 * 0x10):
  682. SyncLightSpotDirection(6);
  683. break;
  684. case PICA_REG_INDEX_WORKAROUND(lighting.light[7].spot_x, 0x146 + 7 * 0x10):
  685. case PICA_REG_INDEX_WORKAROUND(lighting.light[7].spot_z, 0x147 + 7 * 0x10):
  686. SyncLightSpotDirection(7);
  687. break;
  688. // Fragment lighting light source config
  689. case PICA_REG_INDEX_WORKAROUND(lighting.light[0].config, 0x149 + 0 * 0x10):
  690. case PICA_REG_INDEX_WORKAROUND(lighting.light[1].config, 0x149 + 1 * 0x10):
  691. case PICA_REG_INDEX_WORKAROUND(lighting.light[2].config, 0x149 + 2 * 0x10):
  692. case PICA_REG_INDEX_WORKAROUND(lighting.light[3].config, 0x149 + 3 * 0x10):
  693. case PICA_REG_INDEX_WORKAROUND(lighting.light[4].config, 0x149 + 4 * 0x10):
  694. case PICA_REG_INDEX_WORKAROUND(lighting.light[5].config, 0x149 + 5 * 0x10):
  695. case PICA_REG_INDEX_WORKAROUND(lighting.light[6].config, 0x149 + 6 * 0x10):
  696. case PICA_REG_INDEX_WORKAROUND(lighting.light[7].config, 0x149 + 7 * 0x10):
  697. shader_dirty = true;
  698. break;
  699. // Fragment lighting distance attenuation bias
  700. case PICA_REG_INDEX_WORKAROUND(lighting.light[0].dist_atten_bias, 0x014A + 0 * 0x10):
  701. SyncLightDistanceAttenuationBias(0);
  702. break;
  703. case PICA_REG_INDEX_WORKAROUND(lighting.light[1].dist_atten_bias, 0x014A + 1 * 0x10):
  704. SyncLightDistanceAttenuationBias(1);
  705. break;
  706. case PICA_REG_INDEX_WORKAROUND(lighting.light[2].dist_atten_bias, 0x014A + 2 * 0x10):
  707. SyncLightDistanceAttenuationBias(2);
  708. break;
  709. case PICA_REG_INDEX_WORKAROUND(lighting.light[3].dist_atten_bias, 0x014A + 3 * 0x10):
  710. SyncLightDistanceAttenuationBias(3);
  711. break;
  712. case PICA_REG_INDEX_WORKAROUND(lighting.light[4].dist_atten_bias, 0x014A + 4 * 0x10):
  713. SyncLightDistanceAttenuationBias(4);
  714. break;
  715. case PICA_REG_INDEX_WORKAROUND(lighting.light[5].dist_atten_bias, 0x014A + 5 * 0x10):
  716. SyncLightDistanceAttenuationBias(5);
  717. break;
  718. case PICA_REG_INDEX_WORKAROUND(lighting.light[6].dist_atten_bias, 0x014A + 6 * 0x10):
  719. SyncLightDistanceAttenuationBias(6);
  720. break;
  721. case PICA_REG_INDEX_WORKAROUND(lighting.light[7].dist_atten_bias, 0x014A + 7 * 0x10):
  722. SyncLightDistanceAttenuationBias(7);
  723. break;
  724. // Fragment lighting distance attenuation scale
  725. case PICA_REG_INDEX_WORKAROUND(lighting.light[0].dist_atten_scale, 0x014B + 0 * 0x10):
  726. SyncLightDistanceAttenuationScale(0);
  727. break;
  728. case PICA_REG_INDEX_WORKAROUND(lighting.light[1].dist_atten_scale, 0x014B + 1 * 0x10):
  729. SyncLightDistanceAttenuationScale(1);
  730. break;
  731. case PICA_REG_INDEX_WORKAROUND(lighting.light[2].dist_atten_scale, 0x014B + 2 * 0x10):
  732. SyncLightDistanceAttenuationScale(2);
  733. break;
  734. case PICA_REG_INDEX_WORKAROUND(lighting.light[3].dist_atten_scale, 0x014B + 3 * 0x10):
  735. SyncLightDistanceAttenuationScale(3);
  736. break;
  737. case PICA_REG_INDEX_WORKAROUND(lighting.light[4].dist_atten_scale, 0x014B + 4 * 0x10):
  738. SyncLightDistanceAttenuationScale(4);
  739. break;
  740. case PICA_REG_INDEX_WORKAROUND(lighting.light[5].dist_atten_scale, 0x014B + 5 * 0x10):
  741. SyncLightDistanceAttenuationScale(5);
  742. break;
  743. case PICA_REG_INDEX_WORKAROUND(lighting.light[6].dist_atten_scale, 0x014B + 6 * 0x10):
  744. SyncLightDistanceAttenuationScale(6);
  745. break;
  746. case PICA_REG_INDEX_WORKAROUND(lighting.light[7].dist_atten_scale, 0x014B + 7 * 0x10):
  747. SyncLightDistanceAttenuationScale(7);
  748. break;
  749. // Fragment lighting global ambient color (emission + ambient * ambient)
  750. case PICA_REG_INDEX_WORKAROUND(lighting.global_ambient, 0x1c0):
  751. SyncGlobalAmbient();
  752. break;
  753. // Fragment lighting lookup tables
  754. case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[0], 0x1c8):
  755. case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[1], 0x1c9):
  756. case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[2], 0x1ca):
  757. case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[3], 0x1cb):
  758. case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[4], 0x1cc):
  759. case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[5], 0x1cd):
  760. case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[6], 0x1ce):
  761. case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[7], 0x1cf): {
  762. auto& lut_config = regs.lighting.lut_config;
  763. uniform_block_data.lut_dirty[lut_config.type / 4] = true;
  764. break;
  765. }
  766. }
  767. }
  768. void RasterizerOpenGL::FlushAll() {
  769. MICROPROFILE_SCOPE(OpenGL_CacheManagement);
  770. res_cache.FlushAll();
  771. }
  772. void RasterizerOpenGL::FlushRegion(PAddr addr, u32 size) {
  773. MICROPROFILE_SCOPE(OpenGL_CacheManagement);
  774. res_cache.FlushRegion(addr, size, nullptr, false);
  775. }
  776. void RasterizerOpenGL::FlushAndInvalidateRegion(PAddr addr, u32 size) {
  777. MICROPROFILE_SCOPE(OpenGL_CacheManagement);
  778. res_cache.FlushRegion(addr, size, nullptr, true);
  779. }
  780. bool RasterizerOpenGL::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) {
  781. MICROPROFILE_SCOPE(OpenGL_Blits);
  782. CachedSurface src_params;
  783. src_params.addr = config.GetPhysicalInputAddress();
  784. // It's important to use the correct source input width to properly skip over parts of the input
  785. // image which will be cropped from the output but still affect the stride of the input image.
  786. src_params.width = config.input_width;
  787. // Using the output's height is fine because we don't read or skip over the remaining part of
  788. // the image, and it allows for smaller texture cache lookup rectangles.
  789. src_params.height = config.output_height;
  790. src_params.is_tiled = !config.input_linear;
  791. src_params.pixel_format = CachedSurface::PixelFormatFromGPUPixelFormat(config.input_format);
  792. CachedSurface dst_params;
  793. dst_params.addr = config.GetPhysicalOutputAddress();
  794. dst_params.width =
  795. config.scaling != config.NoScale ? config.output_width / 2 : config.output_width.Value();
  796. dst_params.height =
  797. config.scaling == config.ScaleXY ? config.output_height / 2 : config.output_height.Value();
  798. dst_params.is_tiled = config.input_linear != config.dont_swizzle;
  799. dst_params.pixel_format = CachedSurface::PixelFormatFromGPUPixelFormat(config.output_format);
  800. MathUtil::Rectangle<int> src_rect;
  801. CachedSurface* src_surface = res_cache.GetSurfaceRect(src_params, false, true, src_rect);
  802. if (src_surface == nullptr) {
  803. return false;
  804. }
  805. // Adjust the source rectangle to take into account parts of the input lines being cropped
  806. if (config.input_width > config.output_width) {
  807. src_rect.right -= static_cast<int>((config.input_width - config.output_width) *
  808. src_surface->res_scale_width);
  809. }
  810. // Require destination surface to have same resolution scale as source to preserve scaling
  811. dst_params.res_scale_width = src_surface->res_scale_width;
  812. dst_params.res_scale_height = src_surface->res_scale_height;
  813. MathUtil::Rectangle<int> dst_rect;
  814. CachedSurface* dst_surface = res_cache.GetSurfaceRect(dst_params, true, false, dst_rect);
  815. if (dst_surface == nullptr) {
  816. return false;
  817. }
  818. // Don't accelerate if the src and dst surfaces are the same
  819. if (src_surface == dst_surface) {
  820. return false;
  821. }
  822. if (config.flip_vertically) {
  823. std::swap(dst_rect.top, dst_rect.bottom);
  824. }
  825. if (!res_cache.TryBlitSurfaces(src_surface, src_rect, dst_surface, dst_rect)) {
  826. return false;
  827. }
  828. u32 dst_size = dst_params.width * dst_params.height *
  829. CachedSurface::GetFormatBpp(dst_params.pixel_format) / 8;
  830. dst_surface->dirty = true;
  831. res_cache.FlushRegion(config.GetPhysicalOutputAddress(), dst_size, dst_surface, true);
  832. return true;
  833. }
  834. bool RasterizerOpenGL::AccelerateTextureCopy(const GPU::Regs::DisplayTransferConfig& config) {
  835. // TODO(tfarley): Try to hardware accelerate this
  836. return false;
  837. }
  838. bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) {
  839. MICROPROFILE_SCOPE(OpenGL_Blits);
  840. using PixelFormat = CachedSurface::PixelFormat;
  841. using SurfaceType = CachedSurface::SurfaceType;
  842. CachedSurface* dst_surface = res_cache.TryGetFillSurface(config);
  843. if (dst_surface == nullptr) {
  844. return false;
  845. }
  846. OpenGLState cur_state = OpenGLState::GetCurState();
  847. SurfaceType dst_type = CachedSurface::GetFormatType(dst_surface->pixel_format);
  848. GLuint old_fb = cur_state.draw.draw_framebuffer;
  849. cur_state.draw.draw_framebuffer = framebuffer.handle;
  850. // TODO: When scissor test is implemented, need to disable scissor test in cur_state here so
  851. // Clear call isn't affected
  852. cur_state.Apply();
  853. if (dst_type == SurfaceType::Color || dst_type == SurfaceType::Texture) {
  854. glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
  855. dst_surface->texture.handle, 0);
  856. glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
  857. 0);
  858. GLfloat color_values[4] = {0.0f, 0.0f, 0.0f, 0.0f};
  859. // TODO: Handle additional pixel format and fill value size combinations to accelerate more
  860. // cases
  861. // For instance, checking if fill value's bytes/bits repeat to allow filling
  862. // I8/A8/I4/A4/...
  863. // Currently only handles formats that are multiples of the fill value size
  864. if (config.fill_24bit) {
  865. switch (dst_surface->pixel_format) {
  866. case PixelFormat::RGB8:
  867. color_values[0] = config.value_24bit_r / 255.0f;
  868. color_values[1] = config.value_24bit_g / 255.0f;
  869. color_values[2] = config.value_24bit_b / 255.0f;
  870. break;
  871. default:
  872. return false;
  873. }
  874. } else if (config.fill_32bit) {
  875. u32 value = config.value_32bit;
  876. switch (dst_surface->pixel_format) {
  877. case PixelFormat::RGBA8:
  878. color_values[0] = (value >> 24) / 255.0f;
  879. color_values[1] = ((value >> 16) & 0xFF) / 255.0f;
  880. color_values[2] = ((value >> 8) & 0xFF) / 255.0f;
  881. color_values[3] = (value & 0xFF) / 255.0f;
  882. break;
  883. default:
  884. return false;
  885. }
  886. } else {
  887. u16 value_16bit = config.value_16bit.Value();
  888. Math::Vec4<u8> color;
  889. switch (dst_surface->pixel_format) {
  890. case PixelFormat::RGBA8:
  891. color_values[0] = (value_16bit >> 8) / 255.0f;
  892. color_values[1] = (value_16bit & 0xFF) / 255.0f;
  893. color_values[2] = color_values[0];
  894. color_values[3] = color_values[1];
  895. break;
  896. case PixelFormat::RGB5A1:
  897. color = Color::DecodeRGB5A1((const u8*)&value_16bit);
  898. color_values[0] = color[0] / 31.0f;
  899. color_values[1] = color[1] / 31.0f;
  900. color_values[2] = color[2] / 31.0f;
  901. color_values[3] = color[3];
  902. break;
  903. case PixelFormat::RGB565:
  904. color = Color::DecodeRGB565((const u8*)&value_16bit);
  905. color_values[0] = color[0] / 31.0f;
  906. color_values[1] = color[1] / 63.0f;
  907. color_values[2] = color[2] / 31.0f;
  908. break;
  909. case PixelFormat::RGBA4:
  910. color = Color::DecodeRGBA4((const u8*)&value_16bit);
  911. color_values[0] = color[0] / 15.0f;
  912. color_values[1] = color[1] / 15.0f;
  913. color_values[2] = color[2] / 15.0f;
  914. color_values[3] = color[3] / 15.0f;
  915. break;
  916. case PixelFormat::IA8:
  917. case PixelFormat::RG8:
  918. color_values[0] = (value_16bit >> 8) / 255.0f;
  919. color_values[1] = (value_16bit & 0xFF) / 255.0f;
  920. break;
  921. default:
  922. return false;
  923. }
  924. }
  925. cur_state.color_mask.red_enabled = GL_TRUE;
  926. cur_state.color_mask.green_enabled = GL_TRUE;
  927. cur_state.color_mask.blue_enabled = GL_TRUE;
  928. cur_state.color_mask.alpha_enabled = GL_TRUE;
  929. cur_state.Apply();
  930. glClearBufferfv(GL_COLOR, 0, color_values);
  931. } else if (dst_type == SurfaceType::Depth) {
  932. glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
  933. glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
  934. dst_surface->texture.handle, 0);
  935. glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
  936. GLfloat value_float;
  937. if (dst_surface->pixel_format == CachedSurface::PixelFormat::D16) {
  938. value_float = config.value_32bit / 65535.0f; // 2^16 - 1
  939. } else if (dst_surface->pixel_format == CachedSurface::PixelFormat::D24) {
  940. value_float = config.value_32bit / 16777215.0f; // 2^24 - 1
  941. }
  942. cur_state.depth.write_mask = GL_TRUE;
  943. cur_state.Apply();
  944. glClearBufferfv(GL_DEPTH, 0, &value_float);
  945. } else if (dst_type == SurfaceType::DepthStencil) {
  946. glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
  947. glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
  948. dst_surface->texture.handle, 0);
  949. GLfloat value_float = (config.value_32bit & 0xFFFFFF) / 16777215.0f; // 2^24 - 1
  950. GLint value_int = (config.value_32bit >> 24);
  951. cur_state.depth.write_mask = GL_TRUE;
  952. cur_state.stencil.write_mask = 0xFF;
  953. cur_state.Apply();
  954. glClearBufferfi(GL_DEPTH_STENCIL, 0, value_float, value_int);
  955. }
  956. cur_state.draw.draw_framebuffer = old_fb;
  957. // TODO: Return scissor test to previous value when scissor test is implemented
  958. cur_state.Apply();
  959. dst_surface->dirty = true;
  960. res_cache.FlushRegion(dst_surface->addr, dst_surface->size, dst_surface, true);
  961. return true;
  962. }
  963. bool RasterizerOpenGL::AccelerateDisplay(const GPU::Regs::FramebufferConfig& config,
  964. PAddr framebuffer_addr, u32 pixel_stride,
  965. ScreenInfo& screen_info) {
  966. if (framebuffer_addr == 0) {
  967. return false;
  968. }
  969. MICROPROFILE_SCOPE(OpenGL_CacheManagement);
  970. CachedSurface src_params;
  971. src_params.addr = framebuffer_addr;
  972. src_params.width = config.width;
  973. src_params.height = config.height;
  974. src_params.pixel_stride = pixel_stride;
  975. src_params.is_tiled = false;
  976. src_params.pixel_format = CachedSurface::PixelFormatFromGPUPixelFormat(config.color_format);
  977. MathUtil::Rectangle<int> src_rect;
  978. CachedSurface* src_surface = res_cache.GetSurfaceRect(src_params, false, true, src_rect);
  979. if (src_surface == nullptr) {
  980. return false;
  981. }
  982. u32 scaled_width = src_surface->GetScaledWidth();
  983. u32 scaled_height = src_surface->GetScaledHeight();
  984. screen_info.display_texcoords = MathUtil::Rectangle<float>(
  985. (float)src_rect.top / (float)scaled_height, (float)src_rect.left / (float)scaled_width,
  986. (float)src_rect.bottom / (float)scaled_height, (float)src_rect.right / (float)scaled_width);
  987. screen_info.display_texture = src_surface->texture.handle;
  988. return true;
  989. }
  990. void RasterizerOpenGL::SamplerInfo::Create() {
  991. sampler.Create();
  992. mag_filter = min_filter = TextureConfig::Linear;
  993. wrap_s = wrap_t = TextureConfig::Repeat;
  994. border_color = 0;
  995. glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER,
  996. GL_LINEAR); // default is GL_LINEAR_MIPMAP_LINEAR
  997. // Other attributes have correct defaults
  998. }
  999. void RasterizerOpenGL::SamplerInfo::SyncWithConfig(
  1000. const Pica::TexturingRegs::TextureConfig& config) {
  1001. GLuint s = sampler.handle;
  1002. if (mag_filter != config.mag_filter) {
  1003. mag_filter = config.mag_filter;
  1004. glSamplerParameteri(s, GL_TEXTURE_MAG_FILTER, PicaToGL::TextureFilterMode(mag_filter));
  1005. }
  1006. if (min_filter != config.min_filter) {
  1007. min_filter = config.min_filter;
  1008. glSamplerParameteri(s, GL_TEXTURE_MIN_FILTER, PicaToGL::TextureFilterMode(min_filter));
  1009. }
  1010. if (wrap_s != config.wrap_s) {
  1011. wrap_s = config.wrap_s;
  1012. glSamplerParameteri(s, GL_TEXTURE_WRAP_S, PicaToGL::WrapMode(wrap_s));
  1013. }
  1014. if (wrap_t != config.wrap_t) {
  1015. wrap_t = config.wrap_t;
  1016. glSamplerParameteri(s, GL_TEXTURE_WRAP_T, PicaToGL::WrapMode(wrap_t));
  1017. }
  1018. if (wrap_s == TextureConfig::ClampToBorder || wrap_t == TextureConfig::ClampToBorder) {
  1019. if (border_color != config.border_color.raw) {
  1020. border_color = config.border_color.raw;
  1021. auto gl_color = PicaToGL::ColorRGBA8(border_color);
  1022. glSamplerParameterfv(s, GL_TEXTURE_BORDER_COLOR, gl_color.data());
  1023. }
  1024. }
  1025. }
  1026. void RasterizerOpenGL::SetShader() {
  1027. auto config = GLShader::PicaShaderConfig::BuildFromRegs(Pica::g_state.regs);
  1028. std::unique_ptr<PicaShader> shader = std::make_unique<PicaShader>();
  1029. // Find (or generate) the GLSL shader for the current TEV state
  1030. auto cached_shader = shader_cache.find(config);
  1031. if (cached_shader != shader_cache.end()) {
  1032. current_shader = cached_shader->second.get();
  1033. state.draw.shader_program = current_shader->shader.handle;
  1034. state.Apply();
  1035. } else {
  1036. LOG_DEBUG(Render_OpenGL, "Creating new shader");
  1037. shader->shader.Create(GLShader::GenerateVertexShader().c_str(),
  1038. GLShader::GenerateFragmentShader(config).c_str());
  1039. state.draw.shader_program = shader->shader.handle;
  1040. state.Apply();
  1041. // Set the texture samplers to correspond to different texture units
  1042. GLuint uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[0]");
  1043. if (uniform_tex != -1) {
  1044. glUniform1i(uniform_tex, 0);
  1045. }
  1046. uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[1]");
  1047. if (uniform_tex != -1) {
  1048. glUniform1i(uniform_tex, 1);
  1049. }
  1050. uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[2]");
  1051. if (uniform_tex != -1) {
  1052. glUniform1i(uniform_tex, 2);
  1053. }
  1054. // Set the texture samplers to correspond to different lookup table texture units
  1055. GLuint uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[0]");
  1056. if (uniform_lut != -1) {
  1057. glUniform1i(uniform_lut, 3);
  1058. }
  1059. uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[1]");
  1060. if (uniform_lut != -1) {
  1061. glUniform1i(uniform_lut, 4);
  1062. }
  1063. uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[2]");
  1064. if (uniform_lut != -1) {
  1065. glUniform1i(uniform_lut, 5);
  1066. }
  1067. uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[3]");
  1068. if (uniform_lut != -1) {
  1069. glUniform1i(uniform_lut, 6);
  1070. }
  1071. uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[4]");
  1072. if (uniform_lut != -1) {
  1073. glUniform1i(uniform_lut, 7);
  1074. }
  1075. uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[5]");
  1076. if (uniform_lut != -1) {
  1077. glUniform1i(uniform_lut, 8);
  1078. }
  1079. GLuint uniform_fog_lut = glGetUniformLocation(shader->shader.handle, "fog_lut");
  1080. if (uniform_fog_lut != -1) {
  1081. glUniform1i(uniform_fog_lut, 9);
  1082. }
  1083. GLuint uniform_proctex_noise_lut =
  1084. glGetUniformLocation(shader->shader.handle, "proctex_noise_lut");
  1085. if (uniform_proctex_noise_lut != -1) {
  1086. glUniform1i(uniform_proctex_noise_lut, 10);
  1087. }
  1088. GLuint uniform_proctex_color_map =
  1089. glGetUniformLocation(shader->shader.handle, "proctex_color_map");
  1090. if (uniform_proctex_color_map != -1) {
  1091. glUniform1i(uniform_proctex_color_map, 11);
  1092. }
  1093. GLuint uniform_proctex_alpha_map =
  1094. glGetUniformLocation(shader->shader.handle, "proctex_alpha_map");
  1095. if (uniform_proctex_alpha_map != -1) {
  1096. glUniform1i(uniform_proctex_alpha_map, 12);
  1097. }
  1098. GLuint uniform_proctex_lut = glGetUniformLocation(shader->shader.handle, "proctex_lut");
  1099. if (uniform_proctex_lut != -1) {
  1100. glUniform1i(uniform_proctex_lut, 13);
  1101. }
  1102. GLuint uniform_proctex_diff_lut =
  1103. glGetUniformLocation(shader->shader.handle, "proctex_diff_lut");
  1104. if (uniform_proctex_diff_lut != -1) {
  1105. glUniform1i(uniform_proctex_diff_lut, 14);
  1106. }
  1107. current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get();
  1108. GLuint block_index = glGetUniformBlockIndex(current_shader->shader.handle, "shader_data");
  1109. if (block_index != GL_INVALID_INDEX) {
  1110. GLint block_size;
  1111. glGetActiveUniformBlockiv(current_shader->shader.handle, block_index,
  1112. GL_UNIFORM_BLOCK_DATA_SIZE, &block_size);
  1113. ASSERT_MSG(block_size == sizeof(UniformData),
  1114. "Uniform block size did not match! Got %d, expected %zu",
  1115. static_cast<int>(block_size), sizeof(UniformData));
  1116. glUniformBlockBinding(current_shader->shader.handle, block_index, 0);
  1117. // Update uniforms
  1118. SyncDepthScale();
  1119. SyncDepthOffset();
  1120. SyncAlphaTest();
  1121. SyncCombinerColor();
  1122. auto& tev_stages = Pica::g_state.regs.texturing.GetTevStages();
  1123. for (int index = 0; index < tev_stages.size(); ++index)
  1124. SyncTevConstColor(index, tev_stages[index]);
  1125. SyncGlobalAmbient();
  1126. for (int light_index = 0; light_index < 8; light_index++) {
  1127. SyncLightSpecular0(light_index);
  1128. SyncLightSpecular1(light_index);
  1129. SyncLightDiffuse(light_index);
  1130. SyncLightAmbient(light_index);
  1131. SyncLightPosition(light_index);
  1132. SyncLightDistanceAttenuationBias(light_index);
  1133. SyncLightDistanceAttenuationScale(light_index);
  1134. }
  1135. SyncFogColor();
  1136. SyncProcTexNoise();
  1137. }
  1138. }
  1139. }
  1140. void RasterizerOpenGL::SyncCullMode() {
  1141. const auto& regs = Pica::g_state.regs;
  1142. switch (regs.rasterizer.cull_mode) {
  1143. case Pica::RasterizerRegs::CullMode::KeepAll:
  1144. state.cull.enabled = false;
  1145. break;
  1146. case Pica::RasterizerRegs::CullMode::KeepClockWise:
  1147. state.cull.enabled = true;
  1148. state.cull.front_face = GL_CW;
  1149. break;
  1150. case Pica::RasterizerRegs::CullMode::KeepCounterClockWise:
  1151. state.cull.enabled = true;
  1152. state.cull.front_face = GL_CCW;
  1153. break;
  1154. default:
  1155. LOG_CRITICAL(Render_OpenGL, "Unknown cull mode %d", regs.rasterizer.cull_mode.Value());
  1156. UNIMPLEMENTED();
  1157. break;
  1158. }
  1159. }
  1160. void RasterizerOpenGL::SyncDepthScale() {
  1161. float depth_scale =
  1162. Pica::float24::FromRaw(Pica::g_state.regs.rasterizer.viewport_depth_range).ToFloat32();
  1163. if (depth_scale != uniform_block_data.data.depth_scale) {
  1164. uniform_block_data.data.depth_scale = depth_scale;
  1165. uniform_block_data.dirty = true;
  1166. }
  1167. }
  1168. void RasterizerOpenGL::SyncDepthOffset() {
  1169. float depth_offset =
  1170. Pica::float24::FromRaw(Pica::g_state.regs.rasterizer.viewport_depth_near_plane).ToFloat32();
  1171. if (depth_offset != uniform_block_data.data.depth_offset) {
  1172. uniform_block_data.data.depth_offset = depth_offset;
  1173. uniform_block_data.dirty = true;
  1174. }
  1175. }
  1176. void RasterizerOpenGL::SyncBlendEnabled() {
  1177. state.blend.enabled = (Pica::g_state.regs.framebuffer.output_merger.alphablend_enable == 1);
  1178. }
  1179. void RasterizerOpenGL::SyncBlendFuncs() {
  1180. const auto& regs = Pica::g_state.regs;
  1181. state.blend.rgb_equation =
  1182. PicaToGL::BlendEquation(regs.framebuffer.output_merger.alpha_blending.blend_equation_rgb);
  1183. state.blend.a_equation =
  1184. PicaToGL::BlendEquation(regs.framebuffer.output_merger.alpha_blending.blend_equation_a);
  1185. state.blend.src_rgb_func =
  1186. PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_source_rgb);
  1187. state.blend.dst_rgb_func =
  1188. PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_dest_rgb);
  1189. state.blend.src_a_func =
  1190. PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_source_a);
  1191. state.blend.dst_a_func =
  1192. PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_dest_a);
  1193. }
  1194. void RasterizerOpenGL::SyncBlendColor() {
  1195. auto blend_color =
  1196. PicaToGL::ColorRGBA8(Pica::g_state.regs.framebuffer.output_merger.blend_const.raw);
  1197. state.blend.color.red = blend_color[0];
  1198. state.blend.color.green = blend_color[1];
  1199. state.blend.color.blue = blend_color[2];
  1200. state.blend.color.alpha = blend_color[3];
  1201. }
  1202. void RasterizerOpenGL::SyncFogColor() {
  1203. const auto& regs = Pica::g_state.regs;
  1204. uniform_block_data.data.fog_color = {
  1205. regs.texturing.fog_color.r.Value() / 255.0f, regs.texturing.fog_color.g.Value() / 255.0f,
  1206. regs.texturing.fog_color.b.Value() / 255.0f,
  1207. };
  1208. uniform_block_data.dirty = true;
  1209. }
  1210. void RasterizerOpenGL::SyncFogLUT() {
  1211. std::array<GLuint, 128> new_data;
  1212. std::transform(Pica::g_state.fog.lut.begin(), Pica::g_state.fog.lut.end(), new_data.begin(),
  1213. [](const auto& entry) { return entry.raw; });
  1214. if (new_data != fog_lut_data) {
  1215. fog_lut_data = new_data;
  1216. glActiveTexture(GL_TEXTURE9);
  1217. glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 128, GL_RED_INTEGER, GL_UNSIGNED_INT,
  1218. fog_lut_data.data());
  1219. }
  1220. }
  1221. void RasterizerOpenGL::SyncProcTexNoise() {
  1222. const auto& regs = Pica::g_state.regs.texturing;
  1223. uniform_block_data.data.proctex_noise_f = {
  1224. Pica::float16::FromRaw(regs.proctex_noise_frequency.u).ToFloat32(),
  1225. Pica::float16::FromRaw(regs.proctex_noise_frequency.v).ToFloat32(),
  1226. };
  1227. uniform_block_data.data.proctex_noise_a = {
  1228. regs.proctex_noise_u.amplitude / 4095.0f, regs.proctex_noise_v.amplitude / 4095.0f,
  1229. };
  1230. uniform_block_data.data.proctex_noise_p = {
  1231. Pica::float16::FromRaw(regs.proctex_noise_u.phase).ToFloat32(),
  1232. Pica::float16::FromRaw(regs.proctex_noise_v.phase).ToFloat32(),
  1233. };
  1234. uniform_block_data.dirty = true;
  1235. }
  1236. // helper function for SyncProcTexNoiseLUT/ColorMap/AlphaMap
  1237. static void SyncProcTexValueLUT(const std::array<Pica::State::ProcTex::ValueEntry, 128>& lut,
  1238. std::array<GLvec2, 128>& lut_data, GLenum texture) {
  1239. std::array<GLvec2, 128> new_data;
  1240. std::transform(lut.begin(), lut.end(), new_data.begin(), [](const auto& entry) {
  1241. return GLvec2{entry.ToFloat(), entry.DiffToFloat()};
  1242. });
  1243. if (new_data != lut_data) {
  1244. lut_data = new_data;
  1245. glActiveTexture(texture);
  1246. glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 128, GL_RG, GL_FLOAT, lut_data.data());
  1247. }
  1248. }
  1249. void RasterizerOpenGL::SyncProcTexNoiseLUT() {
  1250. SyncProcTexValueLUT(Pica::g_state.proctex.noise_table, proctex_noise_lut_data, GL_TEXTURE10);
  1251. }
  1252. void RasterizerOpenGL::SyncProcTexColorMap() {
  1253. SyncProcTexValueLUT(Pica::g_state.proctex.color_map_table, proctex_color_map_data,
  1254. GL_TEXTURE11);
  1255. }
  1256. void RasterizerOpenGL::SyncProcTexAlphaMap() {
  1257. SyncProcTexValueLUT(Pica::g_state.proctex.alpha_map_table, proctex_alpha_map_data,
  1258. GL_TEXTURE12);
  1259. }
  1260. void RasterizerOpenGL::SyncProcTexLUT() {
  1261. std::array<GLvec4, 256> new_data;
  1262. std::transform(Pica::g_state.proctex.color_table.begin(),
  1263. Pica::g_state.proctex.color_table.end(), new_data.begin(),
  1264. [](const auto& entry) {
  1265. auto rgba = entry.ToVector() / 255.0f;
  1266. return GLvec4{rgba.r(), rgba.g(), rgba.b(), rgba.a()};
  1267. });
  1268. if (new_data != proctex_lut_data) {
  1269. proctex_lut_data = new_data;
  1270. glActiveTexture(GL_TEXTURE13);
  1271. glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_RGBA, GL_FLOAT, proctex_lut_data.data());
  1272. }
  1273. }
  1274. void RasterizerOpenGL::SyncProcTexDiffLUT() {
  1275. std::array<GLvec4, 256> new_data;
  1276. std::transform(Pica::g_state.proctex.color_diff_table.begin(),
  1277. Pica::g_state.proctex.color_diff_table.end(), new_data.begin(),
  1278. [](const auto& entry) {
  1279. auto rgba = entry.ToVector() / 255.0f;
  1280. return GLvec4{rgba.r(), rgba.g(), rgba.b(), rgba.a()};
  1281. });
  1282. if (new_data != proctex_diff_lut_data) {
  1283. proctex_diff_lut_data = new_data;
  1284. glActiveTexture(GL_TEXTURE14);
  1285. glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_RGBA, GL_FLOAT, proctex_diff_lut_data.data());
  1286. }
  1287. }
  1288. void RasterizerOpenGL::SyncAlphaTest() {
  1289. const auto& regs = Pica::g_state.regs;
  1290. if (regs.framebuffer.output_merger.alpha_test.ref != uniform_block_data.data.alphatest_ref) {
  1291. uniform_block_data.data.alphatest_ref = regs.framebuffer.output_merger.alpha_test.ref;
  1292. uniform_block_data.dirty = true;
  1293. }
  1294. }
  1295. void RasterizerOpenGL::SyncLogicOp() {
  1296. state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.framebuffer.output_merger.logic_op);
  1297. }
  1298. void RasterizerOpenGL::SyncColorWriteMask() {
  1299. const auto& regs = Pica::g_state.regs;
  1300. auto IsColorWriteEnabled = [&](u32 value) {
  1301. return (regs.framebuffer.framebuffer.allow_color_write != 0 && value != 0) ? GL_TRUE
  1302. : GL_FALSE;
  1303. };
  1304. state.color_mask.red_enabled = IsColorWriteEnabled(regs.framebuffer.output_merger.red_enable);
  1305. state.color_mask.green_enabled =
  1306. IsColorWriteEnabled(regs.framebuffer.output_merger.green_enable);
  1307. state.color_mask.blue_enabled = IsColorWriteEnabled(regs.framebuffer.output_merger.blue_enable);
  1308. state.color_mask.alpha_enabled =
  1309. IsColorWriteEnabled(regs.framebuffer.output_merger.alpha_enable);
  1310. }
  1311. void RasterizerOpenGL::SyncStencilWriteMask() {
  1312. const auto& regs = Pica::g_state.regs;
  1313. state.stencil.write_mask =
  1314. (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0)
  1315. ? static_cast<GLuint>(regs.framebuffer.output_merger.stencil_test.write_mask)
  1316. : 0;
  1317. }
  1318. void RasterizerOpenGL::SyncDepthWriteMask() {
  1319. const auto& regs = Pica::g_state.regs;
  1320. state.depth.write_mask = (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0 &&
  1321. regs.framebuffer.output_merger.depth_write_enable)
  1322. ? GL_TRUE
  1323. : GL_FALSE;
  1324. }
  1325. void RasterizerOpenGL::SyncStencilTest() {
  1326. const auto& regs = Pica::g_state.regs;
  1327. state.stencil.test_enabled =
  1328. regs.framebuffer.output_merger.stencil_test.enable &&
  1329. regs.framebuffer.framebuffer.depth_format == Pica::FramebufferRegs::DepthFormat::D24S8;
  1330. state.stencil.test_func =
  1331. PicaToGL::CompareFunc(regs.framebuffer.output_merger.stencil_test.func);
  1332. state.stencil.test_ref = regs.framebuffer.output_merger.stencil_test.reference_value;
  1333. state.stencil.test_mask = regs.framebuffer.output_merger.stencil_test.input_mask;
  1334. state.stencil.action_stencil_fail =
  1335. PicaToGL::StencilOp(regs.framebuffer.output_merger.stencil_test.action_stencil_fail);
  1336. state.stencil.action_depth_fail =
  1337. PicaToGL::StencilOp(regs.framebuffer.output_merger.stencil_test.action_depth_fail);
  1338. state.stencil.action_depth_pass =
  1339. PicaToGL::StencilOp(regs.framebuffer.output_merger.stencil_test.action_depth_pass);
  1340. }
  1341. void RasterizerOpenGL::SyncDepthTest() {
  1342. const auto& regs = Pica::g_state.regs;
  1343. state.depth.test_enabled = regs.framebuffer.output_merger.depth_test_enable == 1 ||
  1344. regs.framebuffer.output_merger.depth_write_enable == 1;
  1345. state.depth.test_func =
  1346. regs.framebuffer.output_merger.depth_test_enable == 1
  1347. ? PicaToGL::CompareFunc(regs.framebuffer.output_merger.depth_test_func)
  1348. : GL_ALWAYS;
  1349. }
  1350. void RasterizerOpenGL::SyncCombinerColor() {
  1351. auto combiner_color =
  1352. PicaToGL::ColorRGBA8(Pica::g_state.regs.texturing.tev_combiner_buffer_color.raw);
  1353. if (combiner_color != uniform_block_data.data.tev_combiner_buffer_color) {
  1354. uniform_block_data.data.tev_combiner_buffer_color = combiner_color;
  1355. uniform_block_data.dirty = true;
  1356. }
  1357. }
  1358. void RasterizerOpenGL::SyncTevConstColor(int stage_index,
  1359. const Pica::TexturingRegs::TevStageConfig& tev_stage) {
  1360. auto const_color = PicaToGL::ColorRGBA8(tev_stage.const_color);
  1361. if (const_color != uniform_block_data.data.const_color[stage_index]) {
  1362. uniform_block_data.data.const_color[stage_index] = const_color;
  1363. uniform_block_data.dirty = true;
  1364. }
  1365. }
  1366. void RasterizerOpenGL::SyncGlobalAmbient() {
  1367. auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.global_ambient);
  1368. if (color != uniform_block_data.data.lighting_global_ambient) {
  1369. uniform_block_data.data.lighting_global_ambient = color;
  1370. uniform_block_data.dirty = true;
  1371. }
  1372. }
  1373. void RasterizerOpenGL::SyncLightingLUT(unsigned lut_index) {
  1374. std::array<GLvec4, 256> new_data;
  1375. for (unsigned offset = 0; offset < new_data.size(); ++offset) {
  1376. new_data[offset][0] = Pica::g_state.lighting.luts[(lut_index * 4) + 0][offset].ToFloat();
  1377. new_data[offset][1] = Pica::g_state.lighting.luts[(lut_index * 4) + 1][offset].ToFloat();
  1378. new_data[offset][2] = Pica::g_state.lighting.luts[(lut_index * 4) + 2][offset].ToFloat();
  1379. new_data[offset][3] = Pica::g_state.lighting.luts[(lut_index * 4) + 3][offset].ToFloat();
  1380. }
  1381. if (new_data != lighting_lut_data[lut_index]) {
  1382. lighting_lut_data[lut_index] = new_data;
  1383. glActiveTexture(GL_TEXTURE3 + lut_index);
  1384. glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_RGBA, GL_FLOAT,
  1385. lighting_lut_data[lut_index].data());
  1386. }
  1387. }
  1388. void RasterizerOpenGL::SyncLightSpecular0(int light_index) {
  1389. auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.light[light_index].specular_0);
  1390. if (color != uniform_block_data.data.light_src[light_index].specular_0) {
  1391. uniform_block_data.data.light_src[light_index].specular_0 = color;
  1392. uniform_block_data.dirty = true;
  1393. }
  1394. }
  1395. void RasterizerOpenGL::SyncLightSpecular1(int light_index) {
  1396. auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.light[light_index].specular_1);
  1397. if (color != uniform_block_data.data.light_src[light_index].specular_1) {
  1398. uniform_block_data.data.light_src[light_index].specular_1 = color;
  1399. uniform_block_data.dirty = true;
  1400. }
  1401. }
  1402. void RasterizerOpenGL::SyncLightDiffuse(int light_index) {
  1403. auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.light[light_index].diffuse);
  1404. if (color != uniform_block_data.data.light_src[light_index].diffuse) {
  1405. uniform_block_data.data.light_src[light_index].diffuse = color;
  1406. uniform_block_data.dirty = true;
  1407. }
  1408. }
  1409. void RasterizerOpenGL::SyncLightAmbient(int light_index) {
  1410. auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.light[light_index].ambient);
  1411. if (color != uniform_block_data.data.light_src[light_index].ambient) {
  1412. uniform_block_data.data.light_src[light_index].ambient = color;
  1413. uniform_block_data.dirty = true;
  1414. }
  1415. }
  1416. void RasterizerOpenGL::SyncLightPosition(int light_index) {
  1417. GLvec3 position = {
  1418. Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].x).ToFloat32(),
  1419. Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].y).ToFloat32(),
  1420. Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].z).ToFloat32()};
  1421. if (position != uniform_block_data.data.light_src[light_index].position) {
  1422. uniform_block_data.data.light_src[light_index].position = position;
  1423. uniform_block_data.dirty = true;
  1424. }
  1425. }
  1426. void RasterizerOpenGL::SyncLightSpotDirection(int light_index) {
  1427. const auto& light = Pica::g_state.regs.lighting.light[light_index];
  1428. GLvec3 spot_direction = {light.spot_x / 2047.0f, light.spot_y / 2047.0f,
  1429. light.spot_z / 2047.0f};
  1430. if (spot_direction != uniform_block_data.data.light_src[light_index].spot_direction) {
  1431. uniform_block_data.data.light_src[light_index].spot_direction = spot_direction;
  1432. uniform_block_data.dirty = true;
  1433. }
  1434. }
  1435. void RasterizerOpenGL::SyncLightDistanceAttenuationBias(int light_index) {
  1436. GLfloat dist_atten_bias =
  1437. Pica::float20::FromRaw(Pica::g_state.regs.lighting.light[light_index].dist_atten_bias)
  1438. .ToFloat32();
  1439. if (dist_atten_bias != uniform_block_data.data.light_src[light_index].dist_atten_bias) {
  1440. uniform_block_data.data.light_src[light_index].dist_atten_bias = dist_atten_bias;
  1441. uniform_block_data.dirty = true;
  1442. }
  1443. }
  1444. void RasterizerOpenGL::SyncLightDistanceAttenuationScale(int light_index) {
  1445. GLfloat dist_atten_scale =
  1446. Pica::float20::FromRaw(Pica::g_state.regs.lighting.light[light_index].dist_atten_scale)
  1447. .ToFloat32();
  1448. if (dist_atten_scale != uniform_block_data.data.light_src[light_index].dist_atten_scale) {
  1449. uniform_block_data.data.light_src[light_index].dist_atten_scale = dist_atten_scale;
  1450. uniform_block_data.dirty = true;
  1451. }
  1452. }