gl_rasterizer.cpp 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079
  1. // Copyright 2015 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <array>
  6. #include <bitset>
  7. #include <memory>
  8. #include <string>
  9. #include <string_view>
  10. #include <tuple>
  11. #include <utility>
  12. #include <glad/glad.h>
  13. #include "common/assert.h"
  14. #include "common/logging/log.h"
  15. #include "common/math_util.h"
  16. #include "common/microprofile.h"
  17. #include "common/settings.h"
  18. #include "core/memory.h"
  19. #include "video_core/engines/kepler_compute.h"
  20. #include "video_core/engines/maxwell_3d.h"
  21. #include "video_core/memory_manager.h"
  22. #include "video_core/renderer_opengl/gl_device.h"
  23. #include "video_core/renderer_opengl/gl_query_cache.h"
  24. #include "video_core/renderer_opengl/gl_rasterizer.h"
  25. #include "video_core/renderer_opengl/gl_shader_cache.h"
  26. #include "video_core/renderer_opengl/gl_texture_cache.h"
  27. #include "video_core/renderer_opengl/maxwell_to_gl.h"
  28. #include "video_core/renderer_opengl/renderer_opengl.h"
  29. #include "video_core/shader_cache.h"
  30. #include "video_core/texture_cache/texture_cache_base.h"
  31. namespace OpenGL {
  32. using Maxwell = Tegra::Engines::Maxwell3D::Regs;
  33. using GLvec4 = std::array<GLfloat, 4>;
  34. using VideoCore::Surface::PixelFormat;
  35. using VideoCore::Surface::SurfaceTarget;
  36. using VideoCore::Surface::SurfaceType;
  37. MICROPROFILE_DEFINE(OpenGL_Drawing, "OpenGL", "Drawing", MP_RGB(128, 128, 192));
  38. MICROPROFILE_DEFINE(OpenGL_Clears, "OpenGL", "Clears", MP_RGB(128, 128, 192));
  39. MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(128, 128, 192));
  40. MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Management", MP_RGB(100, 255, 100));
  41. namespace {
  42. constexpr size_t NUM_SUPPORTED_VERTEX_ATTRIBUTES = 16;
  43. void oglEnable(GLenum cap, bool state) {
  44. (state ? glEnable : glDisable)(cap);
  45. }
  46. } // Anonymous namespace
  47. RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_,
  48. Core::Memory::Memory& cpu_memory_, const Device& device_,
  49. ScreenInfo& screen_info_, ProgramManager& program_manager_,
  50. StateTracker& state_tracker_)
  51. : RasterizerAccelerated(cpu_memory_), gpu(gpu_), maxwell3d(gpu.Maxwell3D()),
  52. kepler_compute(gpu.KeplerCompute()), gpu_memory(gpu.MemoryManager()), device(device_),
  53. screen_info(screen_info_), program_manager(program_manager_), state_tracker(state_tracker_),
  54. texture_cache_runtime(device, program_manager, state_tracker),
  55. texture_cache(texture_cache_runtime, *this, maxwell3d, kepler_compute, gpu_memory),
  56. buffer_cache_runtime(device),
  57. buffer_cache(*this, maxwell3d, kepler_compute, gpu_memory, cpu_memory_, buffer_cache_runtime),
  58. shader_cache(*this, emu_window_, maxwell3d, kepler_compute, gpu_memory, device, texture_cache,
  59. buffer_cache, program_manager, state_tracker, gpu.ShaderNotify()),
  60. query_cache(*this, maxwell3d, gpu_memory), accelerate_dma(buffer_cache),
  61. fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache) {}
  62. RasterizerOpenGL::~RasterizerOpenGL() = default;
  63. void RasterizerOpenGL::SyncVertexFormats() {
  64. auto& flags = maxwell3d.dirty.flags;
  65. if (!flags[Dirty::VertexFormats]) {
  66. return;
  67. }
  68. flags[Dirty::VertexFormats] = false;
  69. // Use the vertex array as-is, assumes that the data is formatted correctly for OpenGL. Enables
  70. // the first 16 vertex attributes always, as we don't know which ones are actually used until
  71. // shader time. Note, Tegra technically supports 32, but we're capping this to 16 for now to
  72. // avoid OpenGL errors.
  73. // TODO(Subv): Analyze the shader to identify which attributes are actually used and don't
  74. // assume every shader uses them all.
  75. for (std::size_t index = 0; index < NUM_SUPPORTED_VERTEX_ATTRIBUTES; ++index) {
  76. if (!flags[Dirty::VertexFormat0 + index]) {
  77. continue;
  78. }
  79. flags[Dirty::VertexFormat0 + index] = false;
  80. const auto attrib = maxwell3d.regs.vertex_attrib_format[index];
  81. const auto gl_index = static_cast<GLuint>(index);
  82. // Disable constant attributes.
  83. if (attrib.constant) {
  84. glDisableVertexAttribArray(gl_index);
  85. continue;
  86. }
  87. glEnableVertexAttribArray(gl_index);
  88. if (attrib.type == Maxwell::VertexAttribute::Type::SignedInt ||
  89. attrib.type == Maxwell::VertexAttribute::Type::UnsignedInt) {
  90. glVertexAttribIFormat(gl_index, attrib.ComponentCount(),
  91. MaxwellToGL::VertexFormat(attrib), attrib.offset);
  92. } else {
  93. glVertexAttribFormat(gl_index, attrib.ComponentCount(),
  94. MaxwellToGL::VertexFormat(attrib),
  95. attrib.IsNormalized() ? GL_TRUE : GL_FALSE, attrib.offset);
  96. }
  97. glVertexAttribBinding(gl_index, attrib.buffer);
  98. }
  99. }
  100. void RasterizerOpenGL::SyncVertexInstances() {
  101. auto& flags = maxwell3d.dirty.flags;
  102. if (!flags[Dirty::VertexInstances]) {
  103. return;
  104. }
  105. flags[Dirty::VertexInstances] = false;
  106. const auto& regs = maxwell3d.regs;
  107. for (std::size_t index = 0; index < NUM_SUPPORTED_VERTEX_ATTRIBUTES; ++index) {
  108. if (!flags[Dirty::VertexInstance0 + index]) {
  109. continue;
  110. }
  111. flags[Dirty::VertexInstance0 + index] = false;
  112. const auto gl_index = static_cast<GLuint>(index);
  113. const bool instancing_enabled = regs.instanced_arrays.IsInstancingEnabled(gl_index);
  114. const GLuint divisor = instancing_enabled ? regs.vertex_array[index].divisor : 0;
  115. glVertexBindingDivisor(gl_index, divisor);
  116. }
  117. }
  118. void RasterizerOpenGL::LoadDiskResources(u64 title_id, std::stop_token stop_loading,
  119. const VideoCore::DiskResourceLoadCallback& callback) {
  120. shader_cache.LoadDiskResources(title_id, stop_loading, callback);
  121. }
  122. void RasterizerOpenGL::Clear() {
  123. MICROPROFILE_SCOPE(OpenGL_Clears);
  124. if (!maxwell3d.ShouldExecute()) {
  125. return;
  126. }
  127. const auto& regs = maxwell3d.regs;
  128. bool use_color{};
  129. bool use_depth{};
  130. bool use_stencil{};
  131. if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B ||
  132. regs.clear_buffers.A) {
  133. use_color = true;
  134. const GLuint index = regs.clear_buffers.RT;
  135. state_tracker.NotifyColorMask(index);
  136. glColorMaski(index, regs.clear_buffers.R != 0, regs.clear_buffers.G != 0,
  137. regs.clear_buffers.B != 0, regs.clear_buffers.A != 0);
  138. // TODO(Rodrigo): Determine if clamping is used on clears
  139. SyncFragmentColorClampState();
  140. SyncFramebufferSRGB();
  141. }
  142. if (regs.clear_buffers.Z) {
  143. ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear Z but buffer is not enabled!");
  144. use_depth = true;
  145. state_tracker.NotifyDepthMask();
  146. glDepthMask(GL_TRUE);
  147. }
  148. if (regs.clear_buffers.S) {
  149. ASSERT_MSG(regs.zeta_enable, "Tried to clear stencil but buffer is not enabled!");
  150. use_stencil = true;
  151. }
  152. if (!use_color && !use_depth && !use_stencil) {
  153. // No color surface nor depth/stencil surface are enabled
  154. return;
  155. }
  156. SyncRasterizeEnable();
  157. SyncStencilTestState();
  158. std::scoped_lock lock{texture_cache.mutex};
  159. texture_cache.UpdateRenderTargets(true);
  160. state_tracker.BindFramebuffer(texture_cache.GetFramebuffer()->Handle());
  161. SyncViewport();
  162. if (regs.clear_flags.scissor) {
  163. SyncScissorTest();
  164. } else {
  165. state_tracker.NotifyScissor0();
  166. glDisablei(GL_SCISSOR_TEST, 0);
  167. }
  168. UNIMPLEMENTED_IF(regs.clear_flags.viewport);
  169. if (use_color) {
  170. glClearBufferfv(GL_COLOR, regs.clear_buffers.RT, regs.clear_color);
  171. }
  172. if (use_depth && use_stencil) {
  173. glClearBufferfi(GL_DEPTH_STENCIL, 0, regs.clear_depth, regs.clear_stencil);
  174. } else if (use_depth) {
  175. glClearBufferfv(GL_DEPTH, 0, &regs.clear_depth);
  176. } else if (use_stencil) {
  177. glClearBufferiv(GL_STENCIL, 0, &regs.clear_stencil);
  178. }
  179. ++num_queued_commands;
  180. }
  181. void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
  182. MICROPROFILE_SCOPE(OpenGL_Drawing);
  183. query_cache.UpdateCounters();
  184. GraphicsPipeline* const pipeline{shader_cache.CurrentGraphicsPipeline()};
  185. if (!pipeline) {
  186. return;
  187. }
  188. std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
  189. pipeline->Configure(is_indexed);
  190. SyncState();
  191. const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(maxwell3d.regs.draw.topology);
  192. BeginTransformFeedback(pipeline, primitive_mode);
  193. const GLuint base_instance = static_cast<GLuint>(maxwell3d.regs.vb_base_instance);
  194. const GLsizei num_instances =
  195. static_cast<GLsizei>(is_instanced ? maxwell3d.mme_draw.instance_count : 1);
  196. if (is_indexed) {
  197. const GLint base_vertex = static_cast<GLint>(maxwell3d.regs.vb_element_base);
  198. const GLsizei num_vertices = static_cast<GLsizei>(maxwell3d.regs.index_array.count);
  199. const GLvoid* const offset = buffer_cache_runtime.IndexOffset();
  200. const GLenum format = MaxwellToGL::IndexFormat(maxwell3d.regs.index_array.format);
  201. if (num_instances == 1 && base_instance == 0 && base_vertex == 0) {
  202. glDrawElements(primitive_mode, num_vertices, format, offset);
  203. } else if (num_instances == 1 && base_instance == 0) {
  204. glDrawElementsBaseVertex(primitive_mode, num_vertices, format, offset, base_vertex);
  205. } else if (base_vertex == 0 && base_instance == 0) {
  206. glDrawElementsInstanced(primitive_mode, num_vertices, format, offset, num_instances);
  207. } else if (base_vertex == 0) {
  208. glDrawElementsInstancedBaseInstance(primitive_mode, num_vertices, format, offset,
  209. num_instances, base_instance);
  210. } else if (base_instance == 0) {
  211. glDrawElementsInstancedBaseVertex(primitive_mode, num_vertices, format, offset,
  212. num_instances, base_vertex);
  213. } else {
  214. glDrawElementsInstancedBaseVertexBaseInstance(primitive_mode, num_vertices, format,
  215. offset, num_instances, base_vertex,
  216. base_instance);
  217. }
  218. } else {
  219. const GLint base_vertex = static_cast<GLint>(maxwell3d.regs.vertex_buffer.first);
  220. const GLsizei num_vertices = static_cast<GLsizei>(maxwell3d.regs.vertex_buffer.count);
  221. if (num_instances == 1 && base_instance == 0) {
  222. glDrawArrays(primitive_mode, base_vertex, num_vertices);
  223. } else if (base_instance == 0) {
  224. glDrawArraysInstanced(primitive_mode, base_vertex, num_vertices, num_instances);
  225. } else {
  226. glDrawArraysInstancedBaseInstance(primitive_mode, base_vertex, num_vertices,
  227. num_instances, base_instance);
  228. }
  229. }
  230. EndTransformFeedback();
  231. ++num_queued_commands;
  232. has_written_global_memory |= pipeline->WritesGlobalMemory();
  233. gpu.TickWork();
  234. }
  235. void RasterizerOpenGL::DispatchCompute() {
  236. ComputePipeline* const pipeline{shader_cache.CurrentComputePipeline()};
  237. if (!pipeline) {
  238. return;
  239. }
  240. pipeline->Configure();
  241. const auto& qmd{kepler_compute.launch_description};
  242. glDispatchCompute(qmd.grid_dim_x, qmd.grid_dim_y, qmd.grid_dim_z);
  243. ++num_queued_commands;
  244. has_written_global_memory |= pipeline->WritesGlobalMemory();
  245. }
  246. void RasterizerOpenGL::ResetCounter(VideoCore::QueryType type) {
  247. query_cache.ResetCounter(type);
  248. }
  249. void RasterizerOpenGL::Query(GPUVAddr gpu_addr, VideoCore::QueryType type,
  250. std::optional<u64> timestamp) {
  251. query_cache.Query(gpu_addr, type, timestamp);
  252. }
  253. void RasterizerOpenGL::BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr,
  254. u32 size) {
  255. std::scoped_lock lock{buffer_cache.mutex};
  256. buffer_cache.BindGraphicsUniformBuffer(stage, index, gpu_addr, size);
  257. }
  258. void RasterizerOpenGL::DisableGraphicsUniformBuffer(size_t stage, u32 index) {
  259. buffer_cache.DisableGraphicsUniformBuffer(stage, index);
  260. }
  261. void RasterizerOpenGL::FlushAll() {}
  262. void RasterizerOpenGL::FlushRegion(VAddr addr, u64 size) {
  263. MICROPROFILE_SCOPE(OpenGL_CacheManagement);
  264. if (addr == 0 || size == 0) {
  265. return;
  266. }
  267. {
  268. std::scoped_lock lock{texture_cache.mutex};
  269. texture_cache.DownloadMemory(addr, size);
  270. }
  271. {
  272. std::scoped_lock lock{buffer_cache.mutex};
  273. buffer_cache.DownloadMemory(addr, size);
  274. }
  275. query_cache.FlushRegion(addr, size);
  276. }
  277. bool RasterizerOpenGL::MustFlushRegion(VAddr addr, u64 size) {
  278. std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
  279. if (!Settings::IsGPULevelHigh()) {
  280. return buffer_cache.IsRegionGpuModified(addr, size);
  281. }
  282. return texture_cache.IsRegionGpuModified(addr, size) ||
  283. buffer_cache.IsRegionGpuModified(addr, size);
  284. }
  285. void RasterizerOpenGL::InvalidateRegion(VAddr addr, u64 size) {
  286. MICROPROFILE_SCOPE(OpenGL_CacheManagement);
  287. if (addr == 0 || size == 0) {
  288. return;
  289. }
  290. {
  291. std::scoped_lock lock{texture_cache.mutex};
  292. texture_cache.WriteMemory(addr, size);
  293. }
  294. {
  295. std::scoped_lock lock{buffer_cache.mutex};
  296. buffer_cache.WriteMemory(addr, size);
  297. }
  298. shader_cache.InvalidateRegion(addr, size);
  299. query_cache.InvalidateRegion(addr, size);
  300. }
  301. void RasterizerOpenGL::OnCPUWrite(VAddr addr, u64 size) {
  302. MICROPROFILE_SCOPE(OpenGL_CacheManagement);
  303. if (addr == 0 || size == 0) {
  304. return;
  305. }
  306. shader_cache.OnCPUWrite(addr, size);
  307. {
  308. std::scoped_lock lock{texture_cache.mutex};
  309. texture_cache.WriteMemory(addr, size);
  310. }
  311. {
  312. std::scoped_lock lock{buffer_cache.mutex};
  313. buffer_cache.CachedWriteMemory(addr, size);
  314. }
  315. }
  316. void RasterizerOpenGL::SyncGuestHost() {
  317. MICROPROFILE_SCOPE(OpenGL_CacheManagement);
  318. shader_cache.SyncGuestHost();
  319. {
  320. std::scoped_lock lock{buffer_cache.mutex};
  321. buffer_cache.FlushCachedWrites();
  322. }
  323. }
  324. void RasterizerOpenGL::UnmapMemory(VAddr addr, u64 size) {
  325. {
  326. std::scoped_lock lock{texture_cache.mutex};
  327. texture_cache.UnmapMemory(addr, size);
  328. }
  329. {
  330. std::scoped_lock lock{buffer_cache.mutex};
  331. buffer_cache.WriteMemory(addr, size);
  332. }
  333. shader_cache.OnCPUWrite(addr, size);
  334. }
  335. void RasterizerOpenGL::ModifyGPUMemory(GPUVAddr addr, u64 size) {
  336. {
  337. std::scoped_lock lock{texture_cache.mutex};
  338. texture_cache.UnmapGPUMemory(addr, size);
  339. }
  340. }
  341. void RasterizerOpenGL::SignalSemaphore(GPUVAddr addr, u32 value) {
  342. if (!gpu.IsAsync()) {
  343. gpu_memory.Write<u32>(addr, value);
  344. return;
  345. }
  346. fence_manager.SignalSemaphore(addr, value);
  347. }
  348. void RasterizerOpenGL::SignalSyncPoint(u32 value) {
  349. if (!gpu.IsAsync()) {
  350. gpu.IncrementSyncPoint(value);
  351. return;
  352. }
  353. fence_manager.SignalSyncPoint(value);
  354. }
  355. void RasterizerOpenGL::SignalReference() {
  356. if (!gpu.IsAsync()) {
  357. return;
  358. }
  359. fence_manager.SignalOrdering();
  360. }
  361. void RasterizerOpenGL::ReleaseFences() {
  362. if (!gpu.IsAsync()) {
  363. return;
  364. }
  365. fence_manager.WaitPendingFences();
  366. }
  367. void RasterizerOpenGL::FlushAndInvalidateRegion(VAddr addr, u64 size) {
  368. if (Settings::IsGPULevelExtreme()) {
  369. FlushRegion(addr, size);
  370. }
  371. InvalidateRegion(addr, size);
  372. }
  373. void RasterizerOpenGL::WaitForIdle() {
  374. glMemoryBarrier(GL_ALL_BARRIER_BITS);
  375. SignalReference();
  376. }
  377. void RasterizerOpenGL::FragmentBarrier() {
  378. glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT | GL_TEXTURE_FETCH_BARRIER_BIT);
  379. }
  380. void RasterizerOpenGL::TiledCacheBarrier() {
  381. glTextureBarrier();
  382. }
  383. void RasterizerOpenGL::FlushCommands() {
  384. // Only flush when we have commands queued to OpenGL.
  385. if (num_queued_commands == 0) {
  386. return;
  387. }
  388. num_queued_commands = 0;
  389. // Make sure memory stored from the previous GL command stream is visible
  390. // This is only needed on assembly shaders where we write to GPU memory with raw pointers
  391. if (has_written_global_memory) {
  392. has_written_global_memory = false;
  393. glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
  394. }
  395. glFlush();
  396. }
  397. void RasterizerOpenGL::TickFrame() {
  398. // Ticking a frame means that buffers will be swapped, calling glFlush implicitly.
  399. num_queued_commands = 0;
  400. fence_manager.TickFrame();
  401. {
  402. std::scoped_lock lock{texture_cache.mutex};
  403. texture_cache.TickFrame();
  404. }
  405. {
  406. std::scoped_lock lock{buffer_cache.mutex};
  407. buffer_cache.TickFrame();
  408. }
  409. }
  410. bool RasterizerOpenGL::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surface& src,
  411. const Tegra::Engines::Fermi2D::Surface& dst,
  412. const Tegra::Engines::Fermi2D::Config& copy_config) {
  413. MICROPROFILE_SCOPE(OpenGL_Blits);
  414. std::scoped_lock lock{texture_cache.mutex};
  415. texture_cache.BlitImage(dst, src, copy_config);
  416. return true;
  417. }
  418. Tegra::Engines::AccelerateDMAInterface& RasterizerOpenGL::AccessAccelerateDMA() {
  419. return accelerate_dma;
  420. }
  421. bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
  422. VAddr framebuffer_addr, u32 pixel_stride) {
  423. if (framebuffer_addr == 0) {
  424. return false;
  425. }
  426. MICROPROFILE_SCOPE(OpenGL_CacheManagement);
  427. std::scoped_lock lock{texture_cache.mutex};
  428. ImageView* const image_view{texture_cache.TryFindFramebufferImageView(framebuffer_addr)};
  429. if (!image_view) {
  430. return false;
  431. }
  432. // Verify that the cached surface is the same size and format as the requested framebuffer
  433. // ASSERT_MSG(image_view->size.width == config.width, "Framebuffer width is different");
  434. // ASSERT_MSG(image_view->size.height == config.height, "Framebuffer height is different");
  435. screen_info.display_texture = image_view->Handle(Shader::TextureType::Color2D);
  436. screen_info.display_srgb = VideoCore::Surface::IsPixelFormatSRGB(image_view->format);
  437. return true;
  438. }
  439. void RasterizerOpenGL::SyncState() {
  440. SyncViewport();
  441. SyncRasterizeEnable();
  442. SyncPolygonModes();
  443. SyncColorMask();
  444. SyncFragmentColorClampState();
  445. SyncMultiSampleState();
  446. SyncDepthTestState();
  447. SyncDepthClamp();
  448. SyncStencilTestState();
  449. SyncBlendState();
  450. SyncLogicOpState();
  451. SyncCullMode();
  452. SyncPrimitiveRestart();
  453. SyncScissorTest();
  454. SyncPointState();
  455. SyncLineState();
  456. SyncPolygonOffset();
  457. SyncAlphaTest();
  458. SyncFramebufferSRGB();
  459. SyncVertexFormats();
  460. SyncVertexInstances();
  461. }
  462. void RasterizerOpenGL::SyncViewport() {
  463. auto& flags = maxwell3d.dirty.flags;
  464. const auto& regs = maxwell3d.regs;
  465. const bool rescale_viewports = flags[VideoCommon::Dirty::RescaleViewports];
  466. const bool dirty_viewport = flags[Dirty::Viewports] || rescale_viewports;
  467. const bool dirty_clip_control = flags[Dirty::ClipControl];
  468. if (dirty_clip_control || flags[Dirty::FrontFace]) {
  469. flags[Dirty::FrontFace] = false;
  470. GLenum mode = MaxwellToGL::FrontFace(regs.front_face);
  471. if (regs.screen_y_control.triangle_rast_flip != 0 &&
  472. regs.viewport_transform[0].scale_y < 0.0f) {
  473. switch (mode) {
  474. case GL_CW:
  475. mode = GL_CCW;
  476. break;
  477. case GL_CCW:
  478. mode = GL_CW;
  479. break;
  480. }
  481. }
  482. glFrontFace(mode);
  483. }
  484. if (dirty_viewport || dirty_clip_control) {
  485. flags[Dirty::ClipControl] = false;
  486. bool flip_y = false;
  487. if (regs.viewport_transform[0].scale_y < 0.0f) {
  488. flip_y = !flip_y;
  489. }
  490. if (regs.screen_y_control.y_negate != 0) {
  491. flip_y = !flip_y;
  492. }
  493. const bool is_zero_to_one = regs.depth_mode == Maxwell::DepthMode::ZeroToOne;
  494. const GLenum origin = flip_y ? GL_UPPER_LEFT : GL_LOWER_LEFT;
  495. const GLenum depth = is_zero_to_one ? GL_ZERO_TO_ONE : GL_NEGATIVE_ONE_TO_ONE;
  496. state_tracker.ClipControl(origin, depth);
  497. state_tracker.SetYNegate(regs.screen_y_control.y_negate != 0);
  498. }
  499. const bool is_rescaling{texture_cache.IsRescaling()};
  500. const float scale = is_rescaling ? Settings::values.resolution_info.up_factor : 1.0f;
  501. const auto conv = [scale](float value) -> GLfloat {
  502. float new_value = value * scale;
  503. if (scale < 1.0f) {
  504. const bool sign = std::signbit(value);
  505. new_value = std::round(std::abs(new_value));
  506. new_value = sign ? -new_value : new_value;
  507. }
  508. return static_cast<GLfloat>(new_value);
  509. };
  510. if (dirty_viewport) {
  511. flags[Dirty::Viewports] = false;
  512. const bool force = flags[Dirty::ViewportTransform] || rescale_viewports;
  513. flags[Dirty::ViewportTransform] = false;
  514. flags[VideoCommon::Dirty::RescaleViewports] = false;
  515. for (size_t index = 0; index < Maxwell::NumViewports; ++index) {
  516. if (!force && !flags[Dirty::Viewport0 + index]) {
  517. continue;
  518. }
  519. flags[Dirty::Viewport0 + index] = false;
  520. const auto& src = regs.viewport_transform[index];
  521. GLfloat x = conv(src.translate_x - src.scale_x);
  522. GLfloat y = conv(src.translate_y - src.scale_y);
  523. GLfloat width = conv(src.scale_x * 2.0f);
  524. GLfloat height = conv(src.scale_y * 2.0f);
  525. if (height < 0) {
  526. y += height;
  527. height = -height;
  528. }
  529. glViewportIndexedf(static_cast<GLuint>(index), x, y, width != 0.0f ? width : 1.0f,
  530. height != 0.0f ? height : 1.0f);
  531. const GLdouble reduce_z = regs.depth_mode == Maxwell::DepthMode::MinusOneToOne;
  532. const GLdouble near_depth = src.translate_z - src.scale_z * reduce_z;
  533. const GLdouble far_depth = src.translate_z + src.scale_z;
  534. if (device.HasDepthBufferFloat()) {
  535. glDepthRangeIndexeddNV(static_cast<GLuint>(index), near_depth, far_depth);
  536. } else {
  537. glDepthRangeIndexed(static_cast<GLuint>(index), near_depth, far_depth);
  538. }
  539. if (!GLAD_GL_NV_viewport_swizzle) {
  540. continue;
  541. }
  542. glViewportSwizzleNV(static_cast<GLuint>(index),
  543. MaxwellToGL::ViewportSwizzle(src.swizzle.x),
  544. MaxwellToGL::ViewportSwizzle(src.swizzle.y),
  545. MaxwellToGL::ViewportSwizzle(src.swizzle.z),
  546. MaxwellToGL::ViewportSwizzle(src.swizzle.w));
  547. }
  548. }
  549. }
  550. void RasterizerOpenGL::SyncDepthClamp() {
  551. auto& flags = maxwell3d.dirty.flags;
  552. if (!flags[Dirty::DepthClampEnabled]) {
  553. return;
  554. }
  555. flags[Dirty::DepthClampEnabled] = false;
  556. oglEnable(GL_DEPTH_CLAMP, maxwell3d.regs.view_volume_clip_control.depth_clamp_disabled == 0);
  557. }
  558. void RasterizerOpenGL::SyncClipEnabled(u32 clip_mask) {
  559. auto& flags = maxwell3d.dirty.flags;
  560. if (!flags[Dirty::ClipDistances] && !flags[VideoCommon::Dirty::Shaders]) {
  561. return;
  562. }
  563. flags[Dirty::ClipDistances] = false;
  564. clip_mask &= maxwell3d.regs.clip_distance_enabled;
  565. if (clip_mask == last_clip_distance_mask) {
  566. return;
  567. }
  568. last_clip_distance_mask = clip_mask;
  569. for (std::size_t i = 0; i < Maxwell::Regs::NumClipDistances; ++i) {
  570. oglEnable(static_cast<GLenum>(GL_CLIP_DISTANCE0 + i), (clip_mask >> i) & 1);
  571. }
  572. }
  573. void RasterizerOpenGL::SyncClipCoef() {
  574. UNIMPLEMENTED();
  575. }
  576. void RasterizerOpenGL::SyncCullMode() {
  577. auto& flags = maxwell3d.dirty.flags;
  578. const auto& regs = maxwell3d.regs;
  579. if (flags[Dirty::CullTest]) {
  580. flags[Dirty::CullTest] = false;
  581. if (regs.cull_test_enabled) {
  582. glEnable(GL_CULL_FACE);
  583. glCullFace(MaxwellToGL::CullFace(regs.cull_face));
  584. } else {
  585. glDisable(GL_CULL_FACE);
  586. }
  587. }
  588. }
  589. void RasterizerOpenGL::SyncPrimitiveRestart() {
  590. auto& flags = maxwell3d.dirty.flags;
  591. if (!flags[Dirty::PrimitiveRestart]) {
  592. return;
  593. }
  594. flags[Dirty::PrimitiveRestart] = false;
  595. if (maxwell3d.regs.primitive_restart.enabled) {
  596. glEnable(GL_PRIMITIVE_RESTART);
  597. glPrimitiveRestartIndex(maxwell3d.regs.primitive_restart.index);
  598. } else {
  599. glDisable(GL_PRIMITIVE_RESTART);
  600. }
  601. }
  602. void RasterizerOpenGL::SyncDepthTestState() {
  603. auto& flags = maxwell3d.dirty.flags;
  604. const auto& regs = maxwell3d.regs;
  605. if (flags[Dirty::DepthMask]) {
  606. flags[Dirty::DepthMask] = false;
  607. glDepthMask(regs.depth_write_enabled ? GL_TRUE : GL_FALSE);
  608. }
  609. if (flags[Dirty::DepthTest]) {
  610. flags[Dirty::DepthTest] = false;
  611. if (regs.depth_test_enable) {
  612. glEnable(GL_DEPTH_TEST);
  613. glDepthFunc(MaxwellToGL::ComparisonOp(regs.depth_test_func));
  614. } else {
  615. glDisable(GL_DEPTH_TEST);
  616. }
  617. }
  618. }
  619. void RasterizerOpenGL::SyncStencilTestState() {
  620. auto& flags = maxwell3d.dirty.flags;
  621. if (!flags[Dirty::StencilTest]) {
  622. return;
  623. }
  624. flags[Dirty::StencilTest] = false;
  625. const auto& regs = maxwell3d.regs;
  626. oglEnable(GL_STENCIL_TEST, regs.stencil_enable);
  627. glStencilFuncSeparate(GL_FRONT, MaxwellToGL::ComparisonOp(regs.stencil_front_func_func),
  628. regs.stencil_front_func_ref, regs.stencil_front_func_mask);
  629. glStencilOpSeparate(GL_FRONT, MaxwellToGL::StencilOp(regs.stencil_front_op_fail),
  630. MaxwellToGL::StencilOp(regs.stencil_front_op_zfail),
  631. MaxwellToGL::StencilOp(regs.stencil_front_op_zpass));
  632. glStencilMaskSeparate(GL_FRONT, regs.stencil_front_mask);
  633. if (regs.stencil_two_side_enable) {
  634. glStencilFuncSeparate(GL_BACK, MaxwellToGL::ComparisonOp(regs.stencil_back_func_func),
  635. regs.stencil_back_func_ref, regs.stencil_back_func_mask);
  636. glStencilOpSeparate(GL_BACK, MaxwellToGL::StencilOp(regs.stencil_back_op_fail),
  637. MaxwellToGL::StencilOp(regs.stencil_back_op_zfail),
  638. MaxwellToGL::StencilOp(regs.stencil_back_op_zpass));
  639. glStencilMaskSeparate(GL_BACK, regs.stencil_back_mask);
  640. } else {
  641. glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 0, 0xFFFFFFFF);
  642. glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_KEEP);
  643. glStencilMaskSeparate(GL_BACK, 0xFFFFFFFF);
  644. }
  645. }
  646. void RasterizerOpenGL::SyncRasterizeEnable() {
  647. auto& flags = maxwell3d.dirty.flags;
  648. if (!flags[Dirty::RasterizeEnable]) {
  649. return;
  650. }
  651. flags[Dirty::RasterizeEnable] = false;
  652. oglEnable(GL_RASTERIZER_DISCARD, maxwell3d.regs.rasterize_enable == 0);
  653. }
  654. void RasterizerOpenGL::SyncPolygonModes() {
  655. auto& flags = maxwell3d.dirty.flags;
  656. if (!flags[Dirty::PolygonModes]) {
  657. return;
  658. }
  659. flags[Dirty::PolygonModes] = false;
  660. const auto& regs = maxwell3d.regs;
  661. if (regs.fill_rectangle) {
  662. if (!GLAD_GL_NV_fill_rectangle) {
  663. LOG_ERROR(Render_OpenGL, "GL_NV_fill_rectangle used and not supported");
  664. glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  665. return;
  666. }
  667. flags[Dirty::PolygonModeFront] = true;
  668. flags[Dirty::PolygonModeBack] = true;
  669. glPolygonMode(GL_FRONT_AND_BACK, GL_FILL_RECTANGLE_NV);
  670. return;
  671. }
  672. if (regs.polygon_mode_front == regs.polygon_mode_back) {
  673. flags[Dirty::PolygonModeFront] = false;
  674. flags[Dirty::PolygonModeBack] = false;
  675. glPolygonMode(GL_FRONT_AND_BACK, MaxwellToGL::PolygonMode(regs.polygon_mode_front));
  676. return;
  677. }
  678. if (flags[Dirty::PolygonModeFront]) {
  679. flags[Dirty::PolygonModeFront] = false;
  680. glPolygonMode(GL_FRONT, MaxwellToGL::PolygonMode(regs.polygon_mode_front));
  681. }
  682. if (flags[Dirty::PolygonModeBack]) {
  683. flags[Dirty::PolygonModeBack] = false;
  684. glPolygonMode(GL_BACK, MaxwellToGL::PolygonMode(regs.polygon_mode_back));
  685. }
  686. }
  687. void RasterizerOpenGL::SyncColorMask() {
  688. auto& flags = maxwell3d.dirty.flags;
  689. if (!flags[Dirty::ColorMasks]) {
  690. return;
  691. }
  692. flags[Dirty::ColorMasks] = false;
  693. const bool force = flags[Dirty::ColorMaskCommon];
  694. flags[Dirty::ColorMaskCommon] = false;
  695. const auto& regs = maxwell3d.regs;
  696. if (regs.color_mask_common) {
  697. if (!force && !flags[Dirty::ColorMask0]) {
  698. return;
  699. }
  700. flags[Dirty::ColorMask0] = false;
  701. auto& mask = regs.color_mask[0];
  702. glColorMask(mask.R != 0, mask.B != 0, mask.G != 0, mask.A != 0);
  703. return;
  704. }
  705. // Path without color_mask_common set
  706. for (std::size_t i = 0; i < Maxwell::NumRenderTargets; ++i) {
  707. if (!force && !flags[Dirty::ColorMask0 + i]) {
  708. continue;
  709. }
  710. flags[Dirty::ColorMask0 + i] = false;
  711. const auto& mask = regs.color_mask[i];
  712. glColorMaski(static_cast<GLuint>(i), mask.R != 0, mask.G != 0, mask.B != 0, mask.A != 0);
  713. }
  714. }
  715. void RasterizerOpenGL::SyncMultiSampleState() {
  716. auto& flags = maxwell3d.dirty.flags;
  717. if (!flags[Dirty::MultisampleControl]) {
  718. return;
  719. }
  720. flags[Dirty::MultisampleControl] = false;
  721. const auto& regs = maxwell3d.regs;
  722. oglEnable(GL_SAMPLE_ALPHA_TO_COVERAGE, regs.multisample_control.alpha_to_coverage);
  723. oglEnable(GL_SAMPLE_ALPHA_TO_ONE, regs.multisample_control.alpha_to_one);
  724. }
  725. void RasterizerOpenGL::SyncFragmentColorClampState() {
  726. auto& flags = maxwell3d.dirty.flags;
  727. if (!flags[Dirty::FragmentClampColor]) {
  728. return;
  729. }
  730. flags[Dirty::FragmentClampColor] = false;
  731. glClampColor(GL_CLAMP_FRAGMENT_COLOR, maxwell3d.regs.frag_color_clamp ? GL_TRUE : GL_FALSE);
  732. }
  733. void RasterizerOpenGL::SyncBlendState() {
  734. auto& flags = maxwell3d.dirty.flags;
  735. const auto& regs = maxwell3d.regs;
  736. if (flags[Dirty::BlendColor]) {
  737. flags[Dirty::BlendColor] = false;
  738. glBlendColor(regs.blend_color.r, regs.blend_color.g, regs.blend_color.b,
  739. regs.blend_color.a);
  740. }
  741. // TODO(Rodrigo): Revisit blending, there are several registers we are not reading
  742. if (!flags[Dirty::BlendStates]) {
  743. return;
  744. }
  745. flags[Dirty::BlendStates] = false;
  746. if (!regs.independent_blend_enable) {
  747. if (!regs.blend.enable[0]) {
  748. glDisable(GL_BLEND);
  749. return;
  750. }
  751. glEnable(GL_BLEND);
  752. glBlendFuncSeparate(MaxwellToGL::BlendFunc(regs.blend.factor_source_rgb),
  753. MaxwellToGL::BlendFunc(regs.blend.factor_dest_rgb),
  754. MaxwellToGL::BlendFunc(regs.blend.factor_source_a),
  755. MaxwellToGL::BlendFunc(regs.blend.factor_dest_a));
  756. glBlendEquationSeparate(MaxwellToGL::BlendEquation(regs.blend.equation_rgb),
  757. MaxwellToGL::BlendEquation(regs.blend.equation_a));
  758. return;
  759. }
  760. const bool force = flags[Dirty::BlendIndependentEnabled];
  761. flags[Dirty::BlendIndependentEnabled] = false;
  762. for (std::size_t i = 0; i < Maxwell::NumRenderTargets; ++i) {
  763. if (!force && !flags[Dirty::BlendState0 + i]) {
  764. continue;
  765. }
  766. flags[Dirty::BlendState0 + i] = false;
  767. if (!regs.blend.enable[i]) {
  768. glDisablei(GL_BLEND, static_cast<GLuint>(i));
  769. continue;
  770. }
  771. glEnablei(GL_BLEND, static_cast<GLuint>(i));
  772. const auto& src = regs.independent_blend[i];
  773. glBlendFuncSeparatei(static_cast<GLuint>(i), MaxwellToGL::BlendFunc(src.factor_source_rgb),
  774. MaxwellToGL::BlendFunc(src.factor_dest_rgb),
  775. MaxwellToGL::BlendFunc(src.factor_source_a),
  776. MaxwellToGL::BlendFunc(src.factor_dest_a));
  777. glBlendEquationSeparatei(static_cast<GLuint>(i),
  778. MaxwellToGL::BlendEquation(src.equation_rgb),
  779. MaxwellToGL::BlendEquation(src.equation_a));
  780. }
  781. }
  782. void RasterizerOpenGL::SyncLogicOpState() {
  783. auto& flags = maxwell3d.dirty.flags;
  784. if (!flags[Dirty::LogicOp]) {
  785. return;
  786. }
  787. flags[Dirty::LogicOp] = false;
  788. const auto& regs = maxwell3d.regs;
  789. if (regs.logic_op.enable) {
  790. glEnable(GL_COLOR_LOGIC_OP);
  791. glLogicOp(MaxwellToGL::LogicOp(regs.logic_op.operation));
  792. } else {
  793. glDisable(GL_COLOR_LOGIC_OP);
  794. }
  795. }
  796. void RasterizerOpenGL::SyncScissorTest() {
  797. auto& flags = maxwell3d.dirty.flags;
  798. if (!flags[Dirty::Scissors] && !flags[VideoCommon::Dirty::RescaleScissors]) {
  799. return;
  800. }
  801. flags[Dirty::Scissors] = false;
  802. const bool force = flags[VideoCommon::Dirty::RescaleScissors];
  803. flags[VideoCommon::Dirty::RescaleScissors] = false;
  804. const auto& regs = maxwell3d.regs;
  805. const auto& resolution = Settings::values.resolution_info;
  806. const bool is_rescaling{texture_cache.IsRescaling()};
  807. const u32 up_scale = is_rescaling ? resolution.up_scale : 1U;
  808. const u32 down_shift = is_rescaling ? resolution.down_shift : 0U;
  809. const auto scale_up = [up_scale, down_shift](u32 value) -> u32 {
  810. if (value == 0) {
  811. return 0U;
  812. }
  813. const u32 upset = value * up_scale;
  814. u32 acumm{};
  815. if ((up_scale >> down_shift) == 0) {
  816. acumm = upset % 2;
  817. }
  818. const u32 converted_value = upset >> down_shift;
  819. return std::max<u32>(converted_value + acumm, 1U);
  820. };
  821. for (std::size_t index = 0; index < Maxwell::NumViewports; ++index) {
  822. if (!force && !flags[Dirty::Scissor0 + index]) {
  823. continue;
  824. }
  825. flags[Dirty::Scissor0 + index] = false;
  826. const auto& src = regs.scissor_test[index];
  827. if (src.enable) {
  828. glEnablei(GL_SCISSOR_TEST, static_cast<GLuint>(index));
  829. glScissorIndexed(static_cast<GLuint>(index), scale_up(src.min_x), scale_up(src.min_y),
  830. scale_up(src.max_x - src.min_x), scale_up(src.max_y - src.min_y));
  831. } else {
  832. glDisablei(GL_SCISSOR_TEST, static_cast<GLuint>(index));
  833. }
  834. }
  835. }
  836. void RasterizerOpenGL::SyncPointState() {
  837. auto& flags = maxwell3d.dirty.flags;
  838. if (!flags[Dirty::PointSize]) {
  839. return;
  840. }
  841. flags[Dirty::PointSize] = false;
  842. oglEnable(GL_POINT_SPRITE, maxwell3d.regs.point_sprite_enable);
  843. oglEnable(GL_PROGRAM_POINT_SIZE, maxwell3d.regs.vp_point_size.enable);
  844. const bool is_rescaling{texture_cache.IsRescaling()};
  845. const float scale = is_rescaling ? Settings::values.resolution_info.up_factor : 1.0f;
  846. glPointSize(std::max(1.0f, maxwell3d.regs.point_size * scale));
  847. }
  848. void RasterizerOpenGL::SyncLineState() {
  849. auto& flags = maxwell3d.dirty.flags;
  850. if (!flags[Dirty::LineWidth]) {
  851. return;
  852. }
  853. flags[Dirty::LineWidth] = false;
  854. const auto& regs = maxwell3d.regs;
  855. oglEnable(GL_LINE_SMOOTH, regs.line_smooth_enable);
  856. glLineWidth(regs.line_smooth_enable ? regs.line_width_smooth : regs.line_width_aliased);
  857. }
  858. void RasterizerOpenGL::SyncPolygonOffset() {
  859. auto& flags = maxwell3d.dirty.flags;
  860. if (!flags[Dirty::PolygonOffset]) {
  861. return;
  862. }
  863. flags[Dirty::PolygonOffset] = false;
  864. const auto& regs = maxwell3d.regs;
  865. oglEnable(GL_POLYGON_OFFSET_FILL, regs.polygon_offset_fill_enable);
  866. oglEnable(GL_POLYGON_OFFSET_LINE, regs.polygon_offset_line_enable);
  867. oglEnable(GL_POLYGON_OFFSET_POINT, regs.polygon_offset_point_enable);
  868. if (regs.polygon_offset_fill_enable || regs.polygon_offset_line_enable ||
  869. regs.polygon_offset_point_enable) {
  870. // Hardware divides polygon offset units by two
  871. glPolygonOffsetClamp(regs.polygon_offset_factor, regs.polygon_offset_units / 2.0f,
  872. regs.polygon_offset_clamp);
  873. }
  874. }
  875. void RasterizerOpenGL::SyncAlphaTest() {
  876. auto& flags = maxwell3d.dirty.flags;
  877. if (!flags[Dirty::AlphaTest]) {
  878. return;
  879. }
  880. flags[Dirty::AlphaTest] = false;
  881. const auto& regs = maxwell3d.regs;
  882. if (regs.alpha_test_enabled) {
  883. glEnable(GL_ALPHA_TEST);
  884. glAlphaFunc(MaxwellToGL::ComparisonOp(regs.alpha_test_func), regs.alpha_test_ref);
  885. } else {
  886. glDisable(GL_ALPHA_TEST);
  887. }
  888. }
  889. void RasterizerOpenGL::SyncFramebufferSRGB() {
  890. auto& flags = maxwell3d.dirty.flags;
  891. if (!flags[Dirty::FramebufferSRGB]) {
  892. return;
  893. }
  894. flags[Dirty::FramebufferSRGB] = false;
  895. oglEnable(GL_FRAMEBUFFER_SRGB, maxwell3d.regs.framebuffer_srgb);
  896. }
  897. void RasterizerOpenGL::BeginTransformFeedback(GraphicsPipeline* program, GLenum primitive_mode) {
  898. const auto& regs = maxwell3d.regs;
  899. if (regs.tfb_enabled == 0) {
  900. return;
  901. }
  902. program->ConfigureTransformFeedback();
  903. UNIMPLEMENTED_IF(regs.IsShaderConfigEnabled(Maxwell::ShaderProgram::TesselationControl) ||
  904. regs.IsShaderConfigEnabled(Maxwell::ShaderProgram::TesselationEval) ||
  905. regs.IsShaderConfigEnabled(Maxwell::ShaderProgram::Geometry));
  906. UNIMPLEMENTED_IF(primitive_mode != GL_POINTS);
  907. // We may have to call BeginTransformFeedbackNV here since they seem to call different
  908. // implementations on Nvidia's driver (the pointer is different) but we are using
  909. // ARB_transform_feedback3 features with NV_transform_feedback interactions and the ARB
  910. // extension doesn't define BeginTransformFeedback (without NV) interactions. It just works.
  911. glBeginTransformFeedback(GL_POINTS);
  912. }
  913. void RasterizerOpenGL::EndTransformFeedback() {
  914. if (maxwell3d.regs.tfb_enabled != 0) {
  915. glEndTransformFeedback();
  916. }
  917. }
  918. AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_) : buffer_cache{buffer_cache_} {}
  919. bool AccelerateDMA::BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) {
  920. std::scoped_lock lock{buffer_cache.mutex};
  921. return buffer_cache.DMACopy(src_address, dest_address, amount);
  922. }
  923. bool AccelerateDMA::BufferClear(GPUVAddr src_address, u64 amount, u32 value) {
  924. std::scoped_lock lock{buffer_cache.mutex};
  925. return buffer_cache.DMAClear(src_address, amount, value);
  926. }
  927. } // namespace OpenGL