gl_rasterizer.cpp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913
  1. // Copyright 2015 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <cstring>
  5. #include <memory>
  6. #include <glad/glad.h>
  7. #include "common/color.h"
  8. #include "common/file_util.h"
  9. #include "common/math_util.h"
  10. #include "common/microprofile.h"
  11. #include "common/profiler.h"
  12. #include "core/memory.h"
  13. #include "core/settings.h"
  14. #include "core/hw/gpu.h"
  15. #include "video_core/pica.h"
  16. #include "video_core/utils.h"
  17. #include "video_core/renderer_opengl/gl_rasterizer.h"
  18. #include "video_core/renderer_opengl/gl_shaders.h"
  19. #include "video_core/renderer_opengl/gl_shader_util.h"
  20. #include "video_core/renderer_opengl/pica_to_gl.h"
  21. static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) {
  22. return (stage.color_op == Pica::Regs::TevStageConfig::Operation::Replace &&
  23. stage.alpha_op == Pica::Regs::TevStageConfig::Operation::Replace &&
  24. stage.color_source1 == Pica::Regs::TevStageConfig::Source::Previous &&
  25. stage.alpha_source1 == Pica::Regs::TevStageConfig::Source::Previous &&
  26. stage.color_modifier1 == Pica::Regs::TevStageConfig::ColorModifier::SourceColor &&
  27. stage.alpha_modifier1 == Pica::Regs::TevStageConfig::AlphaModifier::SourceAlpha &&
  28. stage.GetColorMultiplier() == 1 &&
  29. stage.GetAlphaMultiplier() == 1);
  30. }
  31. RasterizerOpenGL::RasterizerOpenGL() : last_fb_color_addr(0), last_fb_depth_addr(0) { }
  32. RasterizerOpenGL::~RasterizerOpenGL() { }
  33. void RasterizerOpenGL::InitObjects() {
  34. // Create sampler objects
  35. for (size_t i = 0; i < texture_samplers.size(); ++i) {
  36. texture_samplers[i].Create();
  37. state.texture_units[i].sampler = texture_samplers[i].sampler.handle;
  38. }
  39. // Generate VBO and VAO
  40. vertex_buffer.Create();
  41. vertex_array.Create();
  42. state.draw.vertex_array = vertex_array.handle;
  43. state.draw.vertex_buffer = vertex_buffer.handle;
  44. state.Apply();
  45. // Set vertex attributes
  46. glVertexAttribPointer(ShaderUtil::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position));
  47. glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_POSITION);
  48. glVertexAttribPointer(ShaderUtil::ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, color));
  49. glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_COLOR);
  50. glVertexAttribPointer(ShaderUtil::ATTRIBUTE_TEXCOORDS, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0));
  51. glVertexAttribPointer(ShaderUtil::ATTRIBUTE_TEXCOORDS + 1, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1));
  52. glVertexAttribPointer(ShaderUtil::ATTRIBUTE_TEXCOORDS + 2, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2));
  53. glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_TEXCOORDS);
  54. glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_TEXCOORDS + 1);
  55. glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_TEXCOORDS + 2);
  56. RegenerateShaders();
  57. // Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation
  58. fb_color_texture.texture.Create();
  59. ReconfigureColorTexture(fb_color_texture, Pica::Regs::ColorFormat::RGBA8, 1, 1);
  60. state.texture_units[0].texture_2d = fb_color_texture.texture.handle;
  61. state.Apply();
  62. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
  63. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  64. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  65. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  66. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  67. state.texture_units[0].texture_2d = 0;
  68. state.Apply();
  69. fb_depth_texture.texture.Create();
  70. ReconfigureDepthTexture(fb_depth_texture, Pica::Regs::DepthFormat::D16, 1, 1);
  71. state.texture_units[0].texture_2d = fb_depth_texture.texture.handle;
  72. state.Apply();
  73. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
  74. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  75. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  76. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  77. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  78. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
  79. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
  80. state.texture_units[0].texture_2d = 0;
  81. state.Apply();
  82. // Configure OpenGL framebuffer
  83. framebuffer.Create();
  84. state.draw.framebuffer = framebuffer.handle;
  85. state.Apply();
  86. glActiveTexture(GL_TEXTURE0);
  87. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb_color_texture.texture.handle, 0);
  88. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, fb_depth_texture.texture.handle, 0);
  89. ASSERT_MSG(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE,
  90. "OpenGL rasterizer framebuffer setup failed, status %X", glCheckFramebufferStatus(GL_FRAMEBUFFER));
  91. }
  92. void RasterizerOpenGL::Reset() {
  93. const auto& regs = Pica::g_state.regs;
  94. SyncCullMode();
  95. SyncBlendEnabled();
  96. SyncBlendFuncs();
  97. SyncBlendColor();
  98. SyncLogicOp();
  99. SyncStencilTest();
  100. SyncDepthTest();
  101. RegenerateShaders();
  102. res_cache.FullFlush();
  103. }
  104. void RasterizerOpenGL::AddTriangle(const Pica::Shader::OutputVertex& v0,
  105. const Pica::Shader::OutputVertex& v1,
  106. const Pica::Shader::OutputVertex& v2) {
  107. vertex_batch.emplace_back(v0);
  108. vertex_batch.emplace_back(v1);
  109. vertex_batch.emplace_back(v2);
  110. }
  111. namespace ShaderCache {
  112. extern std::string GenerateFragmentShader(const ShaderCacheKey& config);
  113. }
  114. void RasterizerOpenGL::RegenerateShaders() {
  115. ShaderCacheKey config = ShaderCacheKey::CurrentShaderConfig();
  116. auto cached_shader = shader_cache.find(config);
  117. if (cached_shader != shader_cache.end()) {
  118. current_shader = &cached_shader->second;
  119. state.draw.shader_program = current_shader->shader.handle;
  120. state.Apply();
  121. } else {
  122. LOG_CRITICAL(Render_OpenGL, "Creating new shader: %08X", hash(config));
  123. TEVShader shader;
  124. std::string fragShader = ShaderCache::GenerateFragmentShader(config);
  125. shader.shader.Create(GLShaders::g_vertex_shader_hw, fragShader.c_str());
  126. shader.uniform_alphatest_ref = glGetUniformLocation(shader.shader.handle, "alphatest_ref");
  127. shader.uniform_tex = glGetUniformLocation(shader.shader.handle, "tex");
  128. shader.uniform_tev_combiner_buffer_color = glGetUniformLocation(shader.shader.handle, "tev_combiner_buffer_color");
  129. shader.uniform_tev_const_colors = glGetUniformLocation(shader.shader.handle, "const_color");
  130. current_shader = &shader_cache.emplace(config, std::move(shader)).first->second;
  131. state.draw.shader_program = current_shader->shader.handle;
  132. state.Apply();
  133. // Set the texture samplers to correspond to different texture units
  134. if (shader.uniform_tex != -1) {
  135. glUniform1i(shader.uniform_tex, 0);
  136. glUniform1i(shader.uniform_tex + 1, 1);
  137. glUniform1i(shader.uniform_tex + 2, 2);
  138. }
  139. }
  140. // Sync alpha reference
  141. if (current_shader->uniform_alphatest_ref != -1)
  142. glUniform1i(current_shader->uniform_alphatest_ref, Pica::g_state.regs.output_merger.alpha_test.ref);
  143. // Sync combiner buffer color
  144. if (current_shader->uniform_tev_combiner_buffer_color != -1) {
  145. auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw);
  146. glUniform4fv(current_shader->uniform_tev_combiner_buffer_color, 1, combiner_color.data());
  147. }
  148. // Sync TEV const colors
  149. if (current_shader->uniform_tev_const_colors != -1) {
  150. auto& tev_stages = Pica::g_state.regs.GetTevStages();
  151. for (int tev_index = 0; tev_index < tev_stages.size(); ++tev_index) {
  152. auto const_color = PicaToGL::ColorRGBA8(tev_stages[tev_index].const_color);
  153. glUniform4fv(current_shader->uniform_tev_const_colors + tev_index, 1, const_color.data());
  154. }
  155. }
  156. }
  157. void RasterizerOpenGL::DrawTriangles() {
  158. SyncFramebuffer();
  159. SyncDrawState();
  160. if (state.draw.shader_dirty) {
  161. RegenerateShaders();
  162. state.draw.shader_dirty = false;
  163. }
  164. glBufferData(GL_ARRAY_BUFFER, vertex_batch.size() * sizeof(HardwareVertex), vertex_batch.data(), GL_STREAM_DRAW);
  165. glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertex_batch.size());
  166. vertex_batch.clear();
  167. // Flush the resource cache at the current depth and color framebuffer addresses for render-to-texture
  168. const auto& regs = Pica::g_state.regs;
  169. PAddr cur_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress();
  170. u32 cur_fb_color_size = Pica::Regs::BytesPerColorPixel(regs.framebuffer.color_format)
  171. * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight();
  172. PAddr cur_fb_depth_addr = regs.framebuffer.GetDepthBufferPhysicalAddress();
  173. u32 cur_fb_depth_size = Pica::Regs::BytesPerDepthPixel(regs.framebuffer.depth_format)
  174. * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight();
  175. res_cache.NotifyFlush(cur_fb_color_addr, cur_fb_color_size, true);
  176. res_cache.NotifyFlush(cur_fb_depth_addr, cur_fb_depth_size, true);
  177. }
  178. void RasterizerOpenGL::CommitFramebuffer() {
  179. CommitColorBuffer();
  180. CommitDepthBuffer();
  181. }
  182. void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
  183. const auto& regs = Pica::g_state.regs;
  184. if (!Settings::values.use_hw_renderer)
  185. return;
  186. switch(id) {
  187. // Culling
  188. case PICA_REG_INDEX(cull_mode):
  189. SyncCullMode();
  190. break;
  191. // Blending
  192. case PICA_REG_INDEX(output_merger.alphablend_enable):
  193. SyncBlendEnabled();
  194. break;
  195. case PICA_REG_INDEX(output_merger.alpha_blending):
  196. SyncBlendFuncs();
  197. break;
  198. case PICA_REG_INDEX(output_merger.blend_const):
  199. SyncBlendColor();
  200. break;
  201. // Alpha test
  202. case PICA_REG_INDEX(output_merger.alpha_test):
  203. SyncAlphaTest();
  204. state.draw.shader_dirty = true;
  205. break;
  206. // Stencil test
  207. case PICA_REG_INDEX(output_merger.stencil_test.raw_func):
  208. case PICA_REG_INDEX(output_merger.stencil_test.raw_op):
  209. SyncStencilTest();
  210. break;
  211. // Depth test
  212. case PICA_REG_INDEX(output_merger.depth_test_enable):
  213. SyncDepthTest();
  214. break;
  215. // Logic op
  216. case PICA_REG_INDEX(output_merger.logic_op):
  217. SyncLogicOp();
  218. break;
  219. // TEV stages
  220. case PICA_REG_INDEX(tev_stage0.color_source1):
  221. case PICA_REG_INDEX(tev_stage0.color_modifier1):
  222. case PICA_REG_INDEX(tev_stage0.color_op):
  223. case PICA_REG_INDEX(tev_stage0.color_scale):
  224. case PICA_REG_INDEX(tev_stage1.color_source1):
  225. case PICA_REG_INDEX(tev_stage1.color_modifier1):
  226. case PICA_REG_INDEX(tev_stage1.color_op):
  227. case PICA_REG_INDEX(tev_stage1.color_scale):
  228. case PICA_REG_INDEX(tev_stage2.color_source1):
  229. case PICA_REG_INDEX(tev_stage2.color_modifier1):
  230. case PICA_REG_INDEX(tev_stage2.color_op):
  231. case PICA_REG_INDEX(tev_stage2.color_scale):
  232. case PICA_REG_INDEX(tev_stage3.color_source1):
  233. case PICA_REG_INDEX(tev_stage3.color_modifier1):
  234. case PICA_REG_INDEX(tev_stage3.color_op):
  235. case PICA_REG_INDEX(tev_stage3.color_scale):
  236. case PICA_REG_INDEX(tev_stage4.color_source1):
  237. case PICA_REG_INDEX(tev_stage4.color_modifier1):
  238. case PICA_REG_INDEX(tev_stage4.color_op):
  239. case PICA_REG_INDEX(tev_stage4.color_scale):
  240. case PICA_REG_INDEX(tev_stage5.color_source1):
  241. case PICA_REG_INDEX(tev_stage5.color_modifier1):
  242. case PICA_REG_INDEX(tev_stage5.color_op):
  243. case PICA_REG_INDEX(tev_stage5.color_scale):
  244. case PICA_REG_INDEX(tev_combiner_buffer_input):
  245. state.draw.shader_dirty = true;
  246. break;
  247. case PICA_REG_INDEX(tev_stage0.const_r):
  248. SyncTevConstColor(0, regs.tev_stage0);
  249. break;
  250. case PICA_REG_INDEX(tev_stage1.const_r):
  251. SyncTevConstColor(1, regs.tev_stage1);
  252. break;
  253. case PICA_REG_INDEX(tev_stage2.const_r):
  254. SyncTevConstColor(2, regs.tev_stage2);
  255. break;
  256. case PICA_REG_INDEX(tev_stage3.const_r):
  257. SyncTevConstColor(3, regs.tev_stage3);
  258. break;
  259. case PICA_REG_INDEX(tev_stage4.const_r):
  260. SyncTevConstColor(4, regs.tev_stage4);
  261. break;
  262. case PICA_REG_INDEX(tev_stage5.const_r):
  263. SyncTevConstColor(5, regs.tev_stage5);
  264. break;
  265. // TEV combiner buffer color
  266. case PICA_REG_INDEX(tev_combiner_buffer_color):
  267. SyncCombinerColor();
  268. break;
  269. }
  270. }
  271. void RasterizerOpenGL::NotifyPreRead(PAddr addr, u32 size) {
  272. const auto& regs = Pica::g_state.regs;
  273. if (!Settings::values.use_hw_renderer)
  274. return;
  275. PAddr cur_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress();
  276. u32 cur_fb_color_size = Pica::Regs::BytesPerColorPixel(regs.framebuffer.color_format)
  277. * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight();
  278. PAddr cur_fb_depth_addr = regs.framebuffer.GetDepthBufferPhysicalAddress();
  279. u32 cur_fb_depth_size = Pica::Regs::BytesPerDepthPixel(regs.framebuffer.depth_format)
  280. * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight();
  281. // If source memory region overlaps 3DS framebuffers, commit them before the copy happens
  282. if (MathUtil::IntervalsIntersect(addr, size, cur_fb_color_addr, cur_fb_color_size))
  283. CommitColorBuffer();
  284. if (MathUtil::IntervalsIntersect(addr, size, cur_fb_depth_addr, cur_fb_depth_size))
  285. CommitDepthBuffer();
  286. }
  287. void RasterizerOpenGL::NotifyFlush(PAddr addr, u32 size) {
  288. const auto& regs = Pica::g_state.regs;
  289. if (!Settings::values.use_hw_renderer)
  290. return;
  291. PAddr cur_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress();
  292. u32 cur_fb_color_size = Pica::Regs::BytesPerColorPixel(regs.framebuffer.color_format)
  293. * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight();
  294. PAddr cur_fb_depth_addr = regs.framebuffer.GetDepthBufferPhysicalAddress();
  295. u32 cur_fb_depth_size = Pica::Regs::BytesPerDepthPixel(regs.framebuffer.depth_format)
  296. * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight();
  297. // If modified memory region overlaps 3DS framebuffers, reload their contents into OpenGL
  298. if (MathUtil::IntervalsIntersect(addr, size, cur_fb_color_addr, cur_fb_color_size))
  299. ReloadColorBuffer();
  300. if (MathUtil::IntervalsIntersect(addr, size, cur_fb_depth_addr, cur_fb_depth_size))
  301. ReloadDepthBuffer();
  302. // Notify cache of flush in case the region touches a cached resource
  303. res_cache.NotifyFlush(addr, size);
  304. }
  305. void RasterizerOpenGL::SamplerInfo::Create() {
  306. sampler.Create();
  307. mag_filter = min_filter = TextureConfig::Linear;
  308. wrap_s = wrap_t = TextureConfig::Repeat;
  309. border_color = 0;
  310. glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // default is GL_LINEAR_MIPMAP_LINEAR
  311. // Other attributes have correct defaults
  312. }
  313. void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Pica::Regs::TextureConfig& config) {
  314. GLuint s = sampler.handle;
  315. if (mag_filter != config.mag_filter) {
  316. mag_filter = config.mag_filter;
  317. glSamplerParameteri(s, GL_TEXTURE_MAG_FILTER, PicaToGL::TextureFilterMode(mag_filter));
  318. }
  319. if (min_filter != config.min_filter) {
  320. min_filter = config.min_filter;
  321. glSamplerParameteri(s, GL_TEXTURE_MIN_FILTER, PicaToGL::TextureFilterMode(min_filter));
  322. }
  323. if (wrap_s != config.wrap_s) {
  324. wrap_s = config.wrap_s;
  325. glSamplerParameteri(s, GL_TEXTURE_WRAP_S, PicaToGL::WrapMode(wrap_s));
  326. }
  327. if (wrap_t != config.wrap_t) {
  328. wrap_t = config.wrap_t;
  329. glSamplerParameteri(s, GL_TEXTURE_WRAP_T, PicaToGL::WrapMode(wrap_t));
  330. }
  331. if (wrap_s == TextureConfig::ClampToBorder || wrap_t == TextureConfig::ClampToBorder) {
  332. if (border_color != config.border_color.raw) {
  333. auto gl_color = PicaToGL::ColorRGBA8(border_color);
  334. glSamplerParameterfv(s, GL_TEXTURE_BORDER_COLOR, gl_color.data());
  335. }
  336. }
  337. }
  338. void RasterizerOpenGL::ReconfigureColorTexture(TextureInfo& texture, Pica::Regs::ColorFormat format, u32 width, u32 height) {
  339. GLint internal_format;
  340. texture.format = format;
  341. texture.width = width;
  342. texture.height = height;
  343. switch (format) {
  344. case Pica::Regs::ColorFormat::RGBA8:
  345. internal_format = GL_RGBA;
  346. texture.gl_format = GL_RGBA;
  347. texture.gl_type = GL_UNSIGNED_INT_8_8_8_8;
  348. break;
  349. case Pica::Regs::ColorFormat::RGB8:
  350. // This pixel format uses BGR since GL_UNSIGNED_BYTE specifies byte-order, unlike every
  351. // specific OpenGL type used in this function using native-endian (that is, little-endian
  352. // mostly everywhere) for words or half-words.
  353. // TODO: check how those behave on big-endian processors.
  354. internal_format = GL_RGB;
  355. texture.gl_format = GL_BGR;
  356. texture.gl_type = GL_UNSIGNED_BYTE;
  357. break;
  358. case Pica::Regs::ColorFormat::RGB5A1:
  359. internal_format = GL_RGBA;
  360. texture.gl_format = GL_RGBA;
  361. texture.gl_type = GL_UNSIGNED_SHORT_5_5_5_1;
  362. break;
  363. case Pica::Regs::ColorFormat::RGB565:
  364. internal_format = GL_RGB;
  365. texture.gl_format = GL_RGB;
  366. texture.gl_type = GL_UNSIGNED_SHORT_5_6_5;
  367. break;
  368. case Pica::Regs::ColorFormat::RGBA4:
  369. internal_format = GL_RGBA;
  370. texture.gl_format = GL_RGBA;
  371. texture.gl_type = GL_UNSIGNED_SHORT_4_4_4_4;
  372. break;
  373. default:
  374. LOG_CRITICAL(Render_OpenGL, "Unknown framebuffer texture color format %x", format);
  375. UNIMPLEMENTED();
  376. break;
  377. }
  378. state.texture_units[0].texture_2d = texture.texture.handle;
  379. state.Apply();
  380. glActiveTexture(GL_TEXTURE0);
  381. glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0,
  382. texture.gl_format, texture.gl_type, nullptr);
  383. state.texture_units[0].texture_2d = 0;
  384. state.Apply();
  385. }
  386. void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height) {
  387. GLint internal_format;
  388. texture.format = format;
  389. texture.width = width;
  390. texture.height = height;
  391. switch (format) {
  392. case Pica::Regs::DepthFormat::D16:
  393. internal_format = GL_DEPTH_COMPONENT16;
  394. texture.gl_format = GL_DEPTH_COMPONENT;
  395. texture.gl_type = GL_UNSIGNED_SHORT;
  396. break;
  397. case Pica::Regs::DepthFormat::D24:
  398. internal_format = GL_DEPTH_COMPONENT24;
  399. texture.gl_format = GL_DEPTH_COMPONENT;
  400. texture.gl_type = GL_UNSIGNED_INT;
  401. break;
  402. case Pica::Regs::DepthFormat::D24S8:
  403. internal_format = GL_DEPTH24_STENCIL8;
  404. texture.gl_format = GL_DEPTH_STENCIL;
  405. texture.gl_type = GL_UNSIGNED_INT_24_8;
  406. break;
  407. default:
  408. LOG_CRITICAL(Render_OpenGL, "Unknown framebuffer texture depth format %x", format);
  409. UNIMPLEMENTED();
  410. break;
  411. }
  412. state.texture_units[0].texture_2d = texture.texture.handle;
  413. state.Apply();
  414. glActiveTexture(GL_TEXTURE0);
  415. glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0,
  416. texture.gl_format, texture.gl_type, nullptr);
  417. state.texture_units[0].texture_2d = 0;
  418. state.Apply();
  419. }
  420. void RasterizerOpenGL::SyncFramebuffer() {
  421. const auto& regs = Pica::g_state.regs;
  422. PAddr cur_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress();
  423. Pica::Regs::ColorFormat new_fb_color_format = regs.framebuffer.color_format;
  424. PAddr cur_fb_depth_addr = regs.framebuffer.GetDepthBufferPhysicalAddress();
  425. Pica::Regs::DepthFormat new_fb_depth_format = regs.framebuffer.depth_format;
  426. bool fb_size_changed = fb_color_texture.width != static_cast<GLsizei>(regs.framebuffer.GetWidth()) ||
  427. fb_color_texture.height != static_cast<GLsizei>(regs.framebuffer.GetHeight());
  428. bool color_fb_prop_changed = fb_color_texture.format != new_fb_color_format ||
  429. fb_size_changed;
  430. bool depth_fb_prop_changed = fb_depth_texture.format != new_fb_depth_format ||
  431. fb_size_changed;
  432. bool color_fb_modified = last_fb_color_addr != cur_fb_color_addr ||
  433. color_fb_prop_changed;
  434. bool depth_fb_modified = last_fb_depth_addr != cur_fb_depth_addr ||
  435. depth_fb_prop_changed;
  436. // Commit if framebuffer modified in any way
  437. if (color_fb_modified)
  438. CommitColorBuffer();
  439. if (depth_fb_modified)
  440. CommitDepthBuffer();
  441. // Reconfigure framebuffer textures if any property has changed
  442. if (color_fb_prop_changed) {
  443. ReconfigureColorTexture(fb_color_texture, new_fb_color_format,
  444. regs.framebuffer.GetWidth(), regs.framebuffer.GetHeight());
  445. }
  446. if (depth_fb_prop_changed) {
  447. ReconfigureDepthTexture(fb_depth_texture, new_fb_depth_format,
  448. regs.framebuffer.GetWidth(), regs.framebuffer.GetHeight());
  449. // Only attach depth buffer as stencil if it supports stencil
  450. switch (new_fb_depth_format) {
  451. case Pica::Regs::DepthFormat::D16:
  452. case Pica::Regs::DepthFormat::D24:
  453. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
  454. break;
  455. case Pica::Regs::DepthFormat::D24S8:
  456. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, fb_depth_texture.texture.handle, 0);
  457. break;
  458. default:
  459. LOG_CRITICAL(Render_OpenGL, "Unknown framebuffer depth format %x", new_fb_depth_format);
  460. UNIMPLEMENTED();
  461. break;
  462. }
  463. }
  464. // Load buffer data again if fb modified in any way
  465. if (color_fb_modified) {
  466. last_fb_color_addr = cur_fb_color_addr;
  467. ReloadColorBuffer();
  468. }
  469. if (depth_fb_modified) {
  470. last_fb_depth_addr = cur_fb_depth_addr;
  471. ReloadDepthBuffer();
  472. }
  473. }
  474. void RasterizerOpenGL::SyncCullMode() {
  475. const auto& regs = Pica::g_state.regs;
  476. switch (regs.cull_mode) {
  477. case Pica::Regs::CullMode::KeepAll:
  478. state.cull.enabled = false;
  479. break;
  480. case Pica::Regs::CullMode::KeepClockWise:
  481. state.cull.enabled = true;
  482. state.cull.mode = GL_BACK;
  483. break;
  484. case Pica::Regs::CullMode::KeepCounterClockWise:
  485. state.cull.enabled = true;
  486. state.cull.mode = GL_FRONT;
  487. break;
  488. default:
  489. LOG_CRITICAL(Render_OpenGL, "Unknown cull mode %d", regs.cull_mode.Value());
  490. UNIMPLEMENTED();
  491. break;
  492. }
  493. }
  494. void RasterizerOpenGL::SyncBlendEnabled() {
  495. state.blend.enabled = (Pica::g_state.regs.output_merger.alphablend_enable == 1);
  496. }
  497. void RasterizerOpenGL::SyncBlendFuncs() {
  498. const auto& regs = Pica::g_state.regs;
  499. state.blend.src_rgb_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_rgb);
  500. state.blend.dst_rgb_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_rgb);
  501. state.blend.src_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_a);
  502. state.blend.dst_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_a);
  503. }
  504. void RasterizerOpenGL::SyncBlendColor() {
  505. auto blend_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.output_merger.blend_const.raw);
  506. state.blend.color.red = blend_color[0];
  507. state.blend.color.green = blend_color[1];
  508. state.blend.color.blue = blend_color[2];
  509. state.blend.color.alpha = blend_color[3];
  510. }
  511. void RasterizerOpenGL::SyncAlphaTest() {
  512. const auto& regs = Pica::g_state.regs;
  513. if (current_shader->uniform_alphatest_ref != -1)
  514. glUniform1i(current_shader->uniform_alphatest_ref, regs.output_merger.alpha_test.ref);
  515. }
  516. void RasterizerOpenGL::SyncLogicOp() {
  517. state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.output_merger.logic_op);
  518. }
  519. void RasterizerOpenGL::SyncStencilTest() {
  520. const auto& regs = Pica::g_state.regs;
  521. state.stencil.test_enabled = regs.output_merger.stencil_test.enable && regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8;
  522. state.stencil.test_func = PicaToGL::CompareFunc(regs.output_merger.stencil_test.func);
  523. state.stencil.test_ref = regs.output_merger.stencil_test.reference_value;
  524. state.stencil.test_mask = regs.output_merger.stencil_test.input_mask;
  525. state.stencil.write_mask = regs.output_merger.stencil_test.write_mask;
  526. state.stencil.action_stencil_fail = PicaToGL::StencilOp(regs.output_merger.stencil_test.action_stencil_fail);
  527. state.stencil.action_depth_fail = PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_fail);
  528. state.stencil.action_depth_pass = PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_pass);
  529. }
  530. void RasterizerOpenGL::SyncDepthTest() {
  531. const auto& regs = Pica::g_state.regs;
  532. state.depth.test_enabled = (regs.output_merger.depth_test_enable == 1);
  533. state.depth.test_func = PicaToGL::CompareFunc(regs.output_merger.depth_test_func);
  534. state.color_mask.red_enabled = regs.output_merger.red_enable;
  535. state.color_mask.green_enabled = regs.output_merger.green_enable;
  536. state.color_mask.blue_enabled = regs.output_merger.blue_enable;
  537. state.color_mask.alpha_enabled = regs.output_merger.alpha_enable;
  538. state.depth.write_mask = regs.output_merger.depth_write_enable ? GL_TRUE : GL_FALSE;
  539. }
  540. void RasterizerOpenGL::SyncCombinerColor() {
  541. if (current_shader->uniform_tev_combiner_buffer_color != -1) {
  542. auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw);
  543. glUniform4fv(current_shader->uniform_tev_combiner_buffer_color, 1, combiner_color.data());
  544. }
  545. }
  546. void RasterizerOpenGL::SyncTevConstColor(int stage_index, const Pica::Regs::TevStageConfig& tev_stage) {
  547. if (current_shader->uniform_tev_const_colors != -1) {
  548. auto const_color = PicaToGL::ColorRGBA8(tev_stage.const_color);
  549. glUniform4fv(current_shader->uniform_tev_const_colors + stage_index, 1, const_color.data());
  550. }
  551. }
  552. void RasterizerOpenGL::SyncDrawState() {
  553. const auto& regs = Pica::g_state.regs;
  554. // Sync the viewport
  555. GLsizei viewport_width = (GLsizei)Pica::float24::FromRawFloat24(regs.viewport_size_x).ToFloat32() * 2;
  556. GLsizei viewport_height = (GLsizei)Pica::float24::FromRawFloat24(regs.viewport_size_y).ToFloat32() * 2;
  557. // OpenGL uses different y coordinates, so negate corner offset and flip origin
  558. // TODO: Ensure viewport_corner.x should not be negated or origin flipped
  559. // TODO: Use floating-point viewports for accuracy if supported
  560. glViewport((GLsizei)static_cast<float>(regs.viewport_corner.x),
  561. -(GLsizei)static_cast<float>(regs.viewport_corner.y)
  562. + regs.framebuffer.GetHeight() - viewport_height,
  563. viewport_width, viewport_height);
  564. // Sync bound texture(s), upload if not cached
  565. const auto pica_textures = regs.GetTextures();
  566. for (unsigned texture_index = 0; texture_index < pica_textures.size(); ++texture_index) {
  567. const auto& texture = pica_textures[texture_index];
  568. if (texture.enabled) {
  569. texture_samplers[texture_index].SyncWithConfig(texture.config);
  570. res_cache.LoadAndBindTexture(state, texture_index, texture);
  571. } else {
  572. state.texture_units[texture_index].texture_2d = 0;
  573. }
  574. }
  575. state.Apply();
  576. }
  577. MICROPROFILE_DEFINE(OpenGL_FramebufferReload, "OpenGL", "FB Reload", MP_RGB(70, 70, 200));
  578. void RasterizerOpenGL::ReloadColorBuffer() {
  579. u8* color_buffer = Memory::GetPhysicalPointer(Pica::g_state.regs.framebuffer.GetColorBufferPhysicalAddress());
  580. if (color_buffer == nullptr)
  581. return;
  582. MICROPROFILE_SCOPE(OpenGL_FramebufferReload);
  583. u32 bytes_per_pixel = Pica::Regs::BytesPerColorPixel(fb_color_texture.format);
  584. std::unique_ptr<u8[]> temp_fb_color_buffer(new u8[fb_color_texture.width * fb_color_texture.height * bytes_per_pixel]);
  585. // Directly copy pixels. Internal OpenGL color formats are consistent so no conversion is necessary.
  586. for (int y = 0; y < fb_color_texture.height; ++y) {
  587. for (int x = 0; x < fb_color_texture.width; ++x) {
  588. const u32 coarse_y = y & ~7;
  589. u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_color_texture.width * bytes_per_pixel;
  590. u32 gl_pixel_index = (x + y * fb_color_texture.width) * bytes_per_pixel;
  591. u8* pixel = color_buffer + dst_offset;
  592. memcpy(&temp_fb_color_buffer[gl_pixel_index], pixel, bytes_per_pixel);
  593. }
  594. }
  595. state.texture_units[0].texture_2d = fb_color_texture.texture.handle;
  596. state.Apply();
  597. glActiveTexture(GL_TEXTURE0);
  598. glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, fb_color_texture.width, fb_color_texture.height,
  599. fb_color_texture.gl_format, fb_color_texture.gl_type, temp_fb_color_buffer.get());
  600. state.texture_units[0].texture_2d = 0;
  601. state.Apply();
  602. }
  603. void RasterizerOpenGL::ReloadDepthBuffer() {
  604. PAddr depth_buffer_addr = Pica::g_state.regs.framebuffer.GetDepthBufferPhysicalAddress();
  605. if (depth_buffer_addr == 0)
  606. return;
  607. // TODO: Appears to work, but double-check endianness of depth values and order of depth-stencil
  608. u8* depth_buffer = Memory::GetPhysicalPointer(depth_buffer_addr);
  609. if (depth_buffer == nullptr)
  610. return;
  611. MICROPROFILE_SCOPE(OpenGL_FramebufferReload);
  612. u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(fb_depth_texture.format);
  613. // OpenGL needs 4 bpp alignment for D24
  614. u32 gl_bpp = bytes_per_pixel == 3 ? 4 : bytes_per_pixel;
  615. std::unique_ptr<u8[]> temp_fb_depth_buffer(new u8[fb_depth_texture.width * fb_depth_texture.height * gl_bpp]);
  616. u8* temp_fb_depth_data = bytes_per_pixel == 3 ? (temp_fb_depth_buffer.get() + 1) : temp_fb_depth_buffer.get();
  617. if (fb_depth_texture.format == Pica::Regs::DepthFormat::D24S8) {
  618. for (int y = 0; y < fb_depth_texture.height; ++y) {
  619. for (int x = 0; x < fb_depth_texture.width; ++x) {
  620. const u32 coarse_y = y & ~7;
  621. u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel;
  622. u32 gl_pixel_index = (x + y * fb_depth_texture.width);
  623. u8* pixel = depth_buffer + dst_offset;
  624. u32 depth_stencil = *(u32*)pixel;
  625. ((u32*)temp_fb_depth_data)[gl_pixel_index] = (depth_stencil << 8) | (depth_stencil >> 24);
  626. }
  627. }
  628. } else {
  629. for (int y = 0; y < fb_depth_texture.height; ++y) {
  630. for (int x = 0; x < fb_depth_texture.width; ++x) {
  631. const u32 coarse_y = y & ~7;
  632. u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel;
  633. u32 gl_pixel_index = (x + y * fb_depth_texture.width) * gl_bpp;
  634. u8* pixel = depth_buffer + dst_offset;
  635. memcpy(&temp_fb_depth_data[gl_pixel_index], pixel, bytes_per_pixel);
  636. }
  637. }
  638. }
  639. state.texture_units[0].texture_2d = fb_depth_texture.texture.handle;
  640. state.Apply();
  641. glActiveTexture(GL_TEXTURE0);
  642. if (fb_depth_texture.format == Pica::Regs::DepthFormat::D24S8) {
  643. // TODO(Subv): There is a bug with Intel Windows drivers that makes glTexSubImage2D not change the stencil buffer.
  644. // The bug has been reported to Intel (https://communities.intel.com/message/324464)
  645. glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, fb_depth_texture.width, fb_depth_texture.height, 0,
  646. GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, temp_fb_depth_buffer.get());
  647. } else {
  648. glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, fb_depth_texture.width, fb_depth_texture.height,
  649. fb_depth_texture.gl_format, fb_depth_texture.gl_type, temp_fb_depth_buffer.get());
  650. }
  651. state.texture_units[0].texture_2d = 0;
  652. state.Apply();
  653. }
  654. Common::Profiling::TimingCategory buffer_commit_category("Framebuffer Commit");
  655. MICROPROFILE_DEFINE(OpenGL_FramebufferCommit, "OpenGL", "FB Commit", MP_RGB(70, 70, 200));
  656. void RasterizerOpenGL::CommitColorBuffer() {
  657. if (last_fb_color_addr != 0) {
  658. u8* color_buffer = Memory::GetPhysicalPointer(last_fb_color_addr);
  659. if (color_buffer != nullptr) {
  660. Common::Profiling::ScopeTimer timer(buffer_commit_category);
  661. MICROPROFILE_SCOPE(OpenGL_FramebufferCommit);
  662. u32 bytes_per_pixel = Pica::Regs::BytesPerColorPixel(fb_color_texture.format);
  663. std::unique_ptr<u8[]> temp_gl_color_buffer(new u8[fb_color_texture.width * fb_color_texture.height * bytes_per_pixel]);
  664. state.texture_units[0].texture_2d = fb_color_texture.texture.handle;
  665. state.Apply();
  666. glActiveTexture(GL_TEXTURE0);
  667. glGetTexImage(GL_TEXTURE_2D, 0, fb_color_texture.gl_format, fb_color_texture.gl_type, temp_gl_color_buffer.get());
  668. state.texture_units[0].texture_2d = 0;
  669. state.Apply();
  670. // Directly copy pixels. Internal OpenGL color formats are consistent so no conversion is necessary.
  671. for (int y = 0; y < fb_color_texture.height; ++y) {
  672. for (int x = 0; x < fb_color_texture.width; ++x) {
  673. const u32 coarse_y = y & ~7;
  674. u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_color_texture.width * bytes_per_pixel;
  675. u32 gl_pixel_index = x * bytes_per_pixel + y * fb_color_texture.width * bytes_per_pixel;
  676. u8* pixel = color_buffer + dst_offset;
  677. memcpy(pixel, &temp_gl_color_buffer[gl_pixel_index], bytes_per_pixel);
  678. }
  679. }
  680. }
  681. }
  682. }
  683. void RasterizerOpenGL::CommitDepthBuffer() {
  684. if (last_fb_depth_addr != 0) {
  685. // TODO: Output seems correct visually, but doesn't quite match sw renderer output. One of them is wrong.
  686. u8* depth_buffer = Memory::GetPhysicalPointer(last_fb_depth_addr);
  687. if (depth_buffer != nullptr) {
  688. Common::Profiling::ScopeTimer timer(buffer_commit_category);
  689. MICROPROFILE_SCOPE(OpenGL_FramebufferCommit);
  690. u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(fb_depth_texture.format);
  691. // OpenGL needs 4 bpp alignment for D24
  692. u32 gl_bpp = bytes_per_pixel == 3 ? 4 : bytes_per_pixel;
  693. std::unique_ptr<u8[]> temp_gl_depth_buffer(new u8[fb_depth_texture.width * fb_depth_texture.height * gl_bpp]);
  694. state.texture_units[0].texture_2d = fb_depth_texture.texture.handle;
  695. state.Apply();
  696. glActiveTexture(GL_TEXTURE0);
  697. glGetTexImage(GL_TEXTURE_2D, 0, fb_depth_texture.gl_format, fb_depth_texture.gl_type, temp_gl_depth_buffer.get());
  698. state.texture_units[0].texture_2d = 0;
  699. state.Apply();
  700. u8* temp_gl_depth_data = bytes_per_pixel == 3 ? (temp_gl_depth_buffer.get() + 1) : temp_gl_depth_buffer.get();
  701. if (fb_depth_texture.format == Pica::Regs::DepthFormat::D24S8) {
  702. for (int y = 0; y < fb_depth_texture.height; ++y) {
  703. for (int x = 0; x < fb_depth_texture.width; ++x) {
  704. const u32 coarse_y = y & ~7;
  705. u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel;
  706. u32 gl_pixel_index = (x + y * fb_depth_texture.width);
  707. u8* pixel = depth_buffer + dst_offset;
  708. u32 depth_stencil = ((u32*)temp_gl_depth_data)[gl_pixel_index];
  709. *(u32*)pixel = (depth_stencil >> 8) | (depth_stencil << 24);
  710. }
  711. }
  712. } else {
  713. for (int y = 0; y < fb_depth_texture.height; ++y) {
  714. for (int x = 0; x < fb_depth_texture.width; ++x) {
  715. const u32 coarse_y = y & ~7;
  716. u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel;
  717. u32 gl_pixel_index = (x + y * fb_depth_texture.width) * gl_bpp;
  718. u8* pixel = depth_buffer + dst_offset;
  719. memcpy(pixel, &temp_gl_depth_data[gl_pixel_index], bytes_per_pixel);
  720. }
  721. }
  722. }
  723. }
  724. }
  725. }