From 63a7be030f716b8e12dd66baa21bf53273c4ed18 Mon Sep 17 00:00:00 2001 From: "Crunch (Chaz9)" Date: Sun, 29 Sep 2024 21:35:55 +0100 Subject: [PATCH] ok --- .../renderer_opengl/gl_rasterizer.cpp | 1045 ++--------------- 1 file changed, 79 insertions(+), 966 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index d376d86d85..e830cee240 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -1,4 +1,5 @@ // SPDX-FileCopyrightText: 2015 Citra Emulator Project +// SPDX-FileCopyrightText: 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include @@ -73,7 +74,8 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra Tegra::MaxwellDeviceMemoryManager& device_memory_, const Device& device_, ProgramManager& program_manager_, StateTracker& state_tracker_) - : gpu(gpu_), device_memory(device_memory_), device(device_), program_manager(program_manager_), + : VideoCommon::OptimizedRasterizer(gpu_, emu_window_), gpu(gpu_), + device_memory(device_memory_), device(device_), program_manager(program_manager_), state_tracker(state_tracker_), texture_cache_runtime(device, program_manager, state_tracker, staging_buffer_pool), texture_cache(texture_cache_runtime, device_memory_), @@ -83,82 +85,62 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra program_manager, state_tracker, gpu.ShaderNotify()), query_cache(*this, device_memory_), accelerate_dma(buffer_cache, texture_cache), fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache), - blit_image(program_manager_) {} + blit_image(program_manager_) { + // Initialize OpenGL-specific features + InitializeOpenGLFeatures(); +} RasterizerOpenGL::~RasterizerOpenGL() = default; -void RasterizerOpenGL::SyncVertexFormats() { - auto& flags = maxwell3d->dirty.flags; - if (!flags[Dirty::VertexFormats]) { - return; - } - flags[Dirty::VertexFormats] = false; +void RasterizerOpenGL::InitializeOpenGLFeatures() { + // Enable additional optimization features + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + glEnable(GL_FRAMEBUFFER_SRGB); + glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); +} - // Use the vertex array as-is, assumes that the data is formatted correctly for OpenGL. Enables - // the first 16 vertex attributes always, as we don't know which ones are actually used until - // shader time. Note, Tegra technically supports 32, but we're capping this to 16 for now to - // avoid OpenGL errors. - // TODO(Subv): Analyze the shader to identify which attributes are actually used and don't - // assume every shader uses them all. - for (std::size_t index = 0; index < NUM_SUPPORTED_VERTEX_ATTRIBUTES; ++index) { - if (!flags[Dirty::VertexFormat0 + index]) { - continue; - } - flags[Dirty::VertexFormat0 + index] = false; +void RasterizerOpenGL::Draw(bool is_indexed, u32 instance_count) { + MICROPROFILE_SCOPE(OpenGL_Drawing); + SCOPE_EXIT { gpu.TickWork(); }; - const auto& attrib = maxwell3d->regs.vertex_attrib_format[index]; - const auto gl_index = static_cast(index); + PrepareDraw(is_indexed, instance_count); - // Disable constant attributes. - if (attrib.constant) { - glDisableVertexAttribArray(gl_index); - continue; - } - glEnableVertexAttribArray(gl_index); + const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(maxwell3d->draw_manager->GetDrawState().topology); + const GLsizei num_instances = static_cast(instance_count); - if (attrib.type == Maxwell::VertexAttribute::Type::SInt || - attrib.type == Maxwell::VertexAttribute::Type::UInt) { - glVertexAttribIFormat(gl_index, attrib.ComponentCount(), - MaxwellToGL::VertexFormat(attrib), attrib.offset); + if (is_indexed) { + const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); + const GLint base_vertex = static_cast(draw_state.base_index); + const GLsizei num_vertices = static_cast(draw_state.index_buffer.count); + const GLvoid* const offset = buffer_cache_runtime.IndexOffset(); + const GLenum format = MaxwellToGL::IndexFormat(draw_state.index_buffer.format); + + if (num_instances == 1 && base_vertex == 0) { + glDrawElements(primitive_mode, num_vertices, format, offset); + } else if (num_instances == 1) { + glDrawElementsBaseVertex(primitive_mode, num_vertices, format, offset, base_vertex); + } else if (base_vertex == 0) { + glDrawElementsInstanced(primitive_mode, num_vertices, format, offset, num_instances); } else { - glVertexAttribFormat(gl_index, attrib.ComponentCount(), - MaxwellToGL::VertexFormat(attrib), - attrib.IsNormalized() ? GL_TRUE : GL_FALSE, attrib.offset); + glDrawElementsInstancedBaseVertex(primitive_mode, num_vertices, format, offset, + num_instances, base_vertex); } - glVertexAttribBinding(gl_index, attrib.buffer); - } -} + } else { + const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); + const GLint base_vertex = static_cast(draw_state.vertex_buffer.first); + const GLsizei num_vertices = static_cast(draw_state.vertex_buffer.count); -void RasterizerOpenGL::SyncVertexInstances() { - auto& flags = maxwell3d->dirty.flags; - if (!flags[Dirty::VertexInstances]) { - return; - } - flags[Dirty::VertexInstances] = false; - - const auto& regs = maxwell3d->regs; - for (std::size_t index = 0; index < NUM_SUPPORTED_VERTEX_ATTRIBUTES; ++index) { - if (!flags[Dirty::VertexInstance0 + index]) { - continue; + if (num_instances == 1) { + glDrawArrays(primitive_mode, base_vertex, num_vertices); + } else { + glDrawArraysInstanced(primitive_mode, base_vertex, num_vertices, num_instances); } - flags[Dirty::VertexInstance0 + index] = false; - - const auto gl_index = static_cast(index); - const bool instancing_enabled = regs.vertex_stream_instances.IsInstancingEnabled(gl_index); - const GLuint divisor = instancing_enabled ? regs.vertex_streams[index].frequency : 0; - glVertexBindingDivisor(gl_index, divisor); } } -void RasterizerOpenGL::LoadDiskResources(u64 title_id, std::stop_token stop_loading, - const VideoCore::DiskResourceLoadCallback& callback) { - shader_cache.LoadDiskResources(title_id, stop_loading, callback); -} - void RasterizerOpenGL::Clear(u32 layer_count) { MICROPROFILE_SCOPE(OpenGL_Clears); - gpu_memory->FlushCaching(); const auto& regs = maxwell3d->regs; bool use_color{}; bool use_depth{}; @@ -173,28 +155,22 @@ void RasterizerOpenGL::Clear(u32 layer_count) { glColorMaski(index, regs.clear_surface.R != 0, regs.clear_surface.G != 0, regs.clear_surface.B != 0, regs.clear_surface.A != 0); - // TODO(Rodrigo): Determine if clamping is used on clears SyncFragmentColorClampState(); SyncFramebufferSRGB(); } if (regs.clear_surface.Z) { - if (regs.zeta_enable != 0) { - LOG_DEBUG(Render_OpenGL, "Tried to clear Z but buffer is not enabled!"); - } + ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear Z but buffer is not enabled!"); use_depth = true; state_tracker.NotifyDepthMask(); glDepthMask(GL_TRUE); } if (regs.clear_surface.S) { - if (regs.zeta_enable) { - LOG_DEBUG(Render_OpenGL, "Tried to clear stencil but buffer is not enabled!"); - } + ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!"); use_stencil = true; } if (!use_color && !use_depth && !use_stencil) { - // No color surface nor depth/stencil surface are enabled return; } @@ -205,13 +181,13 @@ void RasterizerOpenGL::Clear(u32 layer_count) { texture_cache.UpdateRenderTargets(true); state_tracker.BindFramebuffer(texture_cache.GetFramebuffer()->Handle()); SyncViewport(); + if (regs.clear_control.use_scissor) { SyncScissorTest(); } else { state_tracker.NotifyScissor0(); glDisablei(GL_SCISSOR_TEST, 0); } - UNIMPLEMENTED_IF(regs.clear_control.use_viewport_clip0); if (use_color) { glClearBufferfv(GL_COLOR, regs.clear_surface.RT, regs.clear_color.data()); @@ -223,217 +199,30 @@ void RasterizerOpenGL::Clear(u32 layer_count) { } else if (use_stencil) { glClearBufferiv(GL_STENCIL, 0, ®s.clear_stencil); } - ++num_queued_commands; -} - -template -void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) { - MICROPROFILE_SCOPE(OpenGL_Drawing); - - SCOPE_EXIT { - gpu.TickWork(); - }; - gpu_memory->FlushCaching(); - - GraphicsPipeline* const pipeline{shader_cache.CurrentGraphicsPipeline()}; - if (!pipeline) { - return; - } - - gpu.TickWork(); - - std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; - if (pipeline->UsesLocalMemory()) { - program_manager.LocalMemoryWarmup(); - } - pipeline->SetEngine(maxwell3d, gpu_memory); - pipeline->Configure(is_indexed); - - SyncState(); - - const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); - - const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(draw_state.topology); - BeginTransformFeedback(pipeline, primitive_mode); - - draw_func(primitive_mode); - - EndTransformFeedback(); - - ++num_queued_commands; - has_written_global_memory |= pipeline->WritesGlobalMemory(); -} - -void RasterizerOpenGL::Draw(bool is_indexed, u32 instance_count) { - PrepareDraw(is_indexed, [this, is_indexed, instance_count](GLenum primitive_mode) { - const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); - const GLuint base_instance = static_cast(draw_state.base_instance); - const GLsizei num_instances = static_cast(instance_count); - if (is_indexed) { - const GLint base_vertex = static_cast(draw_state.base_index); - const GLsizei num_vertices = static_cast(draw_state.index_buffer.count); - const GLvoid* const offset = buffer_cache_runtime.IndexOffset(); - const GLenum format = MaxwellToGL::IndexFormat(draw_state.index_buffer.format); - if (num_instances == 1 && base_instance == 0 && base_vertex == 0) { - glDrawElements(primitive_mode, num_vertices, format, offset); - } else if (num_instances == 1 && base_instance == 0) { - glDrawElementsBaseVertex(primitive_mode, num_vertices, format, offset, base_vertex); - } else if (base_vertex == 0 && base_instance == 0) { - glDrawElementsInstanced(primitive_mode, num_vertices, format, offset, - num_instances); - } else if (base_vertex == 0) { - glDrawElementsInstancedBaseInstance(primitive_mode, num_vertices, format, offset, - num_instances, base_instance); - } else if (base_instance == 0) { - glDrawElementsInstancedBaseVertex(primitive_mode, num_vertices, format, offset, - num_instances, base_vertex); - } else { - glDrawElementsInstancedBaseVertexBaseInstance(primitive_mode, num_vertices, format, - offset, num_instances, base_vertex, - base_instance); - } - } else { - const GLint base_vertex = static_cast(draw_state.vertex_buffer.first); - const GLsizei num_vertices = static_cast(draw_state.vertex_buffer.count); - if (num_instances == 1 && base_instance == 0) { - glDrawArrays(primitive_mode, base_vertex, num_vertices); - } else if (base_instance == 0) { - glDrawArraysInstanced(primitive_mode, base_vertex, num_vertices, num_instances); - } else { - glDrawArraysInstancedBaseInstance(primitive_mode, base_vertex, num_vertices, - num_instances, base_instance); - } - } - }); -} - -void RasterizerOpenGL::DrawIndirect() { - const auto& params = maxwell3d->draw_manager->GetIndirectParams(); - buffer_cache.SetDrawIndirect(¶ms); - PrepareDraw(params.is_indexed, [this, ¶ms](GLenum primitive_mode) { - if (params.is_byte_count) { - const GPUVAddr tfb_object_base_addr = params.indirect_start_address - 4U; - const GLuint tfb_object = - buffer_cache_runtime.GetTransformFeedbackObject(tfb_object_base_addr); - glDrawTransformFeedback(primitive_mode, tfb_object); - return; - } - const auto [buffer, offset] = buffer_cache.GetDrawIndirectBuffer(); - const GLvoid* const gl_offset = - reinterpret_cast(static_cast(offset)); - glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buffer->Handle()); - if (params.include_count) { - const auto [draw_buffer, offset_base] = buffer_cache.GetDrawIndirectCount(); - glBindBuffer(GL_PARAMETER_BUFFER, draw_buffer->Handle()); - - if (params.is_indexed) { - const GLenum format = MaxwellToGL::IndexFormat(maxwell3d->regs.index_buffer.format); - glMultiDrawElementsIndirectCount(primitive_mode, format, gl_offset, - static_cast(offset_base), - static_cast(params.max_draw_counts), - static_cast(params.stride)); - } else { - glMultiDrawArraysIndirectCount(primitive_mode, gl_offset, - static_cast(offset_base), - static_cast(params.max_draw_counts), - static_cast(params.stride)); - } - return; - } - if (params.is_indexed) { - const GLenum format = MaxwellToGL::IndexFormat(maxwell3d->regs.index_buffer.format); - glMultiDrawElementsIndirect(primitive_mode, format, gl_offset, - static_cast(params.max_draw_counts), - static_cast(params.stride)); - } else { - glMultiDrawArraysIndirect(primitive_mode, gl_offset, - static_cast(params.max_draw_counts), - static_cast(params.stride)); - } - }); - buffer_cache.SetDrawIndirect(nullptr); -} - -void RasterizerOpenGL::DrawTexture() { - MICROPROFILE_SCOPE(OpenGL_Drawing); - - SCOPE_EXIT { - gpu.TickWork(); - }; - - texture_cache.SynchronizeGraphicsDescriptors(); - texture_cache.UpdateRenderTargets(false); - - SyncState(); - - const auto& draw_texture_state = maxwell3d->draw_manager->GetDrawTextureState(); - const auto& sampler = texture_cache.GetGraphicsSampler(draw_texture_state.src_sampler); - const auto& texture = texture_cache.GetImageView(draw_texture_state.src_texture); - - const auto Scale = [&](auto dim) -> s32 { - return Settings::values.resolution_info.ScaleUp(static_cast(dim)); - }; - - Region2D dst_region = { - Offset2D{.x = Scale(draw_texture_state.dst_x0), .y = Scale(draw_texture_state.dst_y0)}, - Offset2D{.x = Scale(draw_texture_state.dst_x1), .y = Scale(draw_texture_state.dst_y1)}}; - Region2D src_region = { - Offset2D{.x = Scale(draw_texture_state.src_x0), .y = Scale(draw_texture_state.src_y0)}, - Offset2D{.x = Scale(draw_texture_state.src_x1), .y = Scale(draw_texture_state.src_y1)}}; - Extent3D src_size = {static_cast(Scale(texture.size.width)), - static_cast(Scale(texture.size.height)), texture.size.depth}; - - if (device.HasDrawTexture()) { - state_tracker.BindFramebuffer(texture_cache.GetFramebuffer()->Handle()); - - glDrawTextureNV(texture.DefaultHandle(), sampler->Handle(), - static_cast(dst_region.start.x), static_cast(dst_region.start.y), - static_cast(dst_region.end.x), static_cast(dst_region.end.y), 0, - draw_texture_state.src_x0 / static_cast(texture.size.width), - draw_texture_state.src_y0 / static_cast(texture.size.height), - draw_texture_state.src_x1 / static_cast(texture.size.width), - draw_texture_state.src_y1 / static_cast(texture.size.height)); - } else { - blit_image.BlitColor(texture_cache.GetFramebuffer()->Handle(), texture.DefaultHandle(), - sampler->Handle(), dst_region, src_region, src_size); - state_tracker.InvalidateState(); - } - - ++num_queued_commands; } void RasterizerOpenGL::DispatchCompute() { - gpu_memory->FlushCaching(); + MICROPROFILE_SCOPE(OpenGL_Drawing); + SCOPE_EXIT { gpu.TickWork(); }; + ComputePipeline* const pipeline{shader_cache.CurrentComputePipeline()}; if (!pipeline) { return; } - if (pipeline->UsesLocalMemory()) { - program_manager.LocalMemoryWarmup(); - } + + std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; pipeline->SetEngine(kepler_compute, gpu_memory); pipeline->Configure(); + const auto& qmd{kepler_compute->launch_description}; - auto indirect_address = kepler_compute->GetIndirectComputeAddress(); - if (indirect_address) { - // DispatchIndirect - static constexpr auto sync_info = VideoCommon::ObtainBufferSynchronize::FullSynchronize; - const auto post_op = VideoCommon::ObtainBufferOperation::DiscardWrite; - const auto [buffer, offset] = - buffer_cache.ObtainBuffer(*indirect_address, 12, sync_info, post_op); - glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, buffer->Handle()); - glDispatchComputeIndirect(static_cast(offset)); - return; - } - glDispatchCompute(qmd.grid_dim_x, qmd.grid_dim_y, qmd.grid_dim_z); - ++num_queued_commands; - has_written_global_memory |= pipeline->WritesGlobalMemory(); + const std::array dim{qmd.grid_dim_x, qmd.grid_dim_y, qmd.grid_dim_z}; + glDispatchCompute(dim[0], dim[1], dim[2]); } void RasterizerOpenGL::ResetCounter(VideoCommon::QueryType type) { const auto query_cache_type = MaxwellToVideoCoreQuery(type); if (!query_cache_type.has_value()) { - UNIMPLEMENTED_IF_MSG(type != VideoCommon::QueryType::Payload, "Reset query type: {}", type); + UNIMPLEMENTED_IF_MSG(type != VideoCommon::QueryType::Payload, "Unsupported query type: {}", type); return; } query_cache.ResetCounter(*query_cache_type); @@ -450,28 +239,6 @@ void RasterizerOpenGL::Query(GPUVAddr gpu_addr, VideoCommon::QueryType type, query_cache.Query(gpu_addr, *query_cache_type, timestamp); } -void RasterizerOpenGL::QueryFallback(GPUVAddr gpu_addr, VideoCommon::QueryType type, - VideoCommon::QueryPropertiesFlags flags, u32 payload, - u32 subreport) { - if (type != VideoCommon::QueryType::Payload) { - payload = 1u; - } - std::function func([this, gpu_addr, flags, memory_manager = gpu_memory, payload]() { - if (True(flags & VideoCommon::QueryPropertiesFlags::HasTimeout)) { - u64 ticks = gpu.GetTicks(); - memory_manager->Write(gpu_addr + 8, ticks); - memory_manager->Write(gpu_addr, static_cast(payload)); - } else { - memory_manager->Write(gpu_addr, payload); - } - }); - if (True(flags & VideoCommon::QueryPropertiesFlags::IsAFence)) { - SignalFence(std::move(func)); - return; - } - func(); -} - void RasterizerOpenGL::BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size) { std::scoped_lock lock{buffer_cache.mutex}; @@ -520,26 +287,29 @@ bool RasterizerOpenGL::MustFlushRegion(DAddr addr, u64 size, VideoCommon::CacheT } VideoCore::RasterizerDownloadArea RasterizerOpenGL::GetFlushArea(DAddr addr, u64 size) { + VideoCore::RasterizerDownloadArea result{ + .start_address = Common::AlignDown(addr, Core::DEVICE_PAGESIZE), + .end_address = Common::AlignUp(addr + size, Core::DEVICE_PAGESIZE), + .preemtive = true, + }; { std::scoped_lock lock{texture_cache.mutex}; auto area = texture_cache.GetFlushArea(addr, size); if (area) { - return *area; + result = *area; + result.preemtive = false; } } { std::scoped_lock lock{buffer_cache.mutex}; auto area = buffer_cache.GetFlushArea(addr, size); if (area) { - return *area; + result.start_address = std::min(result.start_address, area->start_address); + result.end_address = std::max(result.end_address, area->end_address); + result.preemtive = false; } } - VideoCore::RasterizerDownloadArea new_area{ - .start_address = Common::AlignDown(addr, Core::DEVICE_PAGESIZE), - .end_address = Common::AlignUp(addr + size, Core::DEVICE_PAGESIZE), - .preemtive = true, - }; - return new_area; + return result; } void RasterizerOpenGL::InvalidateRegion(DAddr addr, u64 size, VideoCommon::CacheType which) { @@ -603,7 +373,16 @@ void RasterizerOpenGL::OnCacheInvalidation(DAddr addr, u64 size) { } void RasterizerOpenGL::InvalidateGPUCache() { - gpu.InvalidateGPUCache(); + gpu_memory->FlushCaching(); + shader_cache.SyncGuestHost(); + { + std::scoped_lock lock{buffer_cache.mutex}; + buffer_cache.FlushCachedWrites(); + } + { + std::scoped_lock lock{texture_cache.mutex}; + texture_cache.FlushCachedWrites(); + } } void RasterizerOpenGL::UnmapMemory(DAddr addr, u64 size) { @@ -673,13 +452,6 @@ void RasterizerOpenGL::FlushCommands() { return; } num_queued_commands = 0; - - // Make sure memory stored from the previous GL command stream is visible - // This is only needed on assembly shaders where we write to GPU memory with raw pointers - if (has_written_global_memory) { - has_written_global_memory = false; - glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); - } glFlush(); } @@ -701,7 +473,6 @@ void RasterizerOpenGL::TickFrame() { bool RasterizerOpenGL::AccelerateConditionalRendering() { gpu_memory->FlushCaching(); if (Settings::IsGPULevelHigh()) { - // Reimplement Host conditional rendering. return false; } // Medium / Low Hack: stub any checks on queries written into the buffer cache. @@ -730,7 +501,7 @@ void RasterizerOpenGL::AccelerateInlineToMemory(GPUVAddr address, size_t copy_si std::span memory) { auto cpu_addr = gpu_memory->GpuToCpuAddress(address); if (!cpu_addr) [[unlikely]] { - gpu_memory->WriteBlock(address, memory.data(), copy_size); + gpu_memory->WriteBlockUnsafe(address, memory.data(), copy_size); return; } gpu_memory->WriteBlockUnsafe(address, memory.data(), copy_size); @@ -748,609 +519,9 @@ void RasterizerOpenGL::AccelerateInlineToMemory(GPUVAddr address, size_t copy_si query_cache.InvalidateRegion(*cpu_addr, copy_size); } -std::optional RasterizerOpenGL::AccelerateDisplay( - const Tegra::FramebufferConfig& config, DAddr framebuffer_addr, u32 pixel_stride) { - if (framebuffer_addr == 0) { - return {}; - } - MICROPROFILE_SCOPE(OpenGL_CacheManagement); - - std::scoped_lock lock{texture_cache.mutex}; - const auto [image_view, scaled] = - texture_cache.TryFindFramebufferImageView(config, framebuffer_addr); - if (!image_view) { - return {}; - } - - const auto& resolution = Settings::values.resolution_info; - - FramebufferTextureInfo info{}; - info.display_texture = image_view->Handle(Shader::TextureType::Color2D); - info.width = image_view->size.width; - info.height = image_view->size.height; - info.scaled_width = scaled ? resolution.ScaleUp(info.width) : info.width; - info.scaled_height = scaled ? resolution.ScaleUp(info.height) : info.height; - return info; -} - -void RasterizerOpenGL::SyncState() { - SyncViewport(); - SyncRasterizeEnable(); - SyncPolygonModes(); - SyncColorMask(); - SyncFragmentColorClampState(); - SyncMultiSampleState(); - SyncDepthTestState(); - SyncDepthClamp(); - SyncStencilTestState(); - SyncBlendState(); - SyncLogicOpState(); - SyncCullMode(); - SyncPrimitiveRestart(); - SyncScissorTest(); - SyncPointState(); - SyncLineState(); - SyncPolygonOffset(); - SyncAlphaTest(); - SyncFramebufferSRGB(); - SyncVertexFormats(); - SyncVertexInstances(); -} - -void RasterizerOpenGL::SyncViewport() { - auto& flags = maxwell3d->dirty.flags; - const auto& regs = maxwell3d->regs; - - const bool rescale_viewports = flags[VideoCommon::Dirty::RescaleViewports]; - const bool dirty_viewport = flags[Dirty::Viewports] || rescale_viewports; - const bool dirty_clip_control = flags[Dirty::ClipControl]; - - if (dirty_viewport || dirty_clip_control || flags[Dirty::FrontFace]) { - flags[Dirty::FrontFace] = false; - - GLenum mode = MaxwellToGL::FrontFace(regs.gl_front_face); - bool flip_faces = true; - if (regs.window_origin.flip_y != 0) { - flip_faces = !flip_faces; - } - if (regs.viewport_transform[0].scale_y < 0.0f) { - flip_faces = !flip_faces; - } - if (flip_faces) { - switch (mode) { - case GL_CW: - mode = GL_CCW; - break; - case GL_CCW: - mode = GL_CW; - break; - } - } - glFrontFace(mode); - } - if (dirty_viewport || dirty_clip_control) { - flags[Dirty::ClipControl] = false; - - bool flip_y = false; - if (regs.viewport_transform[0].scale_y < 0.0f) { - flip_y = !flip_y; - } - const bool lower_left{regs.window_origin.mode != Maxwell::WindowOrigin::Mode::UpperLeft}; - if (lower_left) { - flip_y = !flip_y; - } - const bool is_zero_to_one = regs.depth_mode == Maxwell::DepthMode::ZeroToOne; - const GLenum origin = flip_y ? GL_UPPER_LEFT : GL_LOWER_LEFT; - const GLenum depth = is_zero_to_one ? GL_ZERO_TO_ONE : GL_NEGATIVE_ONE_TO_ONE; - state_tracker.ClipControl(origin, depth); - state_tracker.SetYNegate(lower_left); - } - const bool is_rescaling{texture_cache.IsRescaling()}; - const float scale = is_rescaling ? Settings::values.resolution_info.up_factor : 1.0f; - const auto conv = [scale](float value) -> GLfloat { - float new_value = value * scale; - if (scale < 1.0f) { - const bool sign = std::signbit(value); - new_value = std::round(std::abs(new_value)); - new_value = sign ? -new_value : new_value; - } - return static_cast(new_value); - }; - - if (dirty_viewport) { - flags[Dirty::Viewports] = false; - - const bool force = flags[Dirty::ViewportTransform] || rescale_viewports; - flags[Dirty::ViewportTransform] = false; - flags[VideoCommon::Dirty::RescaleViewports] = false; - - for (size_t index = 0; index < Maxwell::NumViewports; ++index) { - if (!force && !flags[Dirty::Viewport0 + index]) { - continue; - } - flags[Dirty::Viewport0 + index] = false; - - if (!regs.viewport_scale_offset_enabled) { - const auto x = static_cast(regs.surface_clip.x); - const auto y = static_cast(regs.surface_clip.y); - const auto width = static_cast(regs.surface_clip.width); - const auto height = static_cast(regs.surface_clip.height); - glViewportIndexedf(static_cast(index), x, y, width != 0.0f ? width : 1.0f, - height != 0.0f ? height : 1.0f); - continue; - } - - const auto& src = regs.viewport_transform[index]; - GLfloat x = conv(src.translate_x - src.scale_x); - GLfloat y = conv(src.translate_y - src.scale_y); - GLfloat width = conv(src.scale_x * 2.0f); - GLfloat height = conv(src.scale_y * 2.0f); - - if (height < 0) { - y += height; - height = -height; - } - glViewportIndexedf(static_cast(index), x, y, width != 0.0f ? width : 1.0f, - height != 0.0f ? height : 1.0f); - - const GLdouble reduce_z = regs.depth_mode == Maxwell::DepthMode::MinusOneToOne; - const GLdouble near_depth = src.translate_z - src.scale_z * reduce_z; - const GLdouble far_depth = src.translate_z + src.scale_z; - if (device.HasDepthBufferFloat()) { - glDepthRangeIndexeddNV(static_cast(index), near_depth, far_depth); - } else { - glDepthRangeIndexed(static_cast(index), near_depth, far_depth); - } - - if (!GLAD_GL_NV_viewport_swizzle) { - continue; - } - glViewportSwizzleNV(static_cast(index), - MaxwellToGL::ViewportSwizzle(src.swizzle.x), - MaxwellToGL::ViewportSwizzle(src.swizzle.y), - MaxwellToGL::ViewportSwizzle(src.swizzle.z), - MaxwellToGL::ViewportSwizzle(src.swizzle.w)); - } - } -} - -void RasterizerOpenGL::SyncDepthClamp() { - auto& flags = maxwell3d->dirty.flags; - if (!flags[Dirty::DepthClampEnabled]) { - return; - } - flags[Dirty::DepthClampEnabled] = false; - - bool depth_clamp_disabled{maxwell3d->regs.viewport_clip_control.geometry_clip == - Maxwell::ViewportClipControl::GeometryClip::Passthrough || - maxwell3d->regs.viewport_clip_control.geometry_clip == - Maxwell::ViewportClipControl::GeometryClip::FrustumXYZ || - maxwell3d->regs.viewport_clip_control.geometry_clip == - Maxwell::ViewportClipControl::GeometryClip::FrustumZ}; - oglEnable(GL_DEPTH_CLAMP, !depth_clamp_disabled); -} - -void RasterizerOpenGL::SyncClipEnabled(u32 clip_mask) { - auto& flags = maxwell3d->dirty.flags; - if (!flags[Dirty::ClipDistances] && !flags[VideoCommon::Dirty::Shaders]) { - return; - } - flags[Dirty::ClipDistances] = false; - - clip_mask &= maxwell3d->regs.user_clip_enable.raw; - if (clip_mask == last_clip_distance_mask) { - return; - } - last_clip_distance_mask = clip_mask; - - for (std::size_t i = 0; i < Maxwell::Regs::NumClipDistances; ++i) { - oglEnable(static_cast(GL_CLIP_DISTANCE0 + i), (clip_mask >> i) & 1); - } -} - -void RasterizerOpenGL::SyncClipCoef() { - UNIMPLEMENTED(); -} - -void RasterizerOpenGL::SyncCullMode() { - auto& flags = maxwell3d->dirty.flags; - const auto& regs = maxwell3d->regs; - - if (flags[Dirty::CullTest]) { - flags[Dirty::CullTest] = false; - - if (regs.gl_cull_test_enabled) { - glEnable(GL_CULL_FACE); - glCullFace(MaxwellToGL::CullFace(regs.gl_cull_face)); - } else { - glDisable(GL_CULL_FACE); - } - } -} - -void RasterizerOpenGL::SyncPrimitiveRestart() { - auto& flags = maxwell3d->dirty.flags; - if (!flags[Dirty::PrimitiveRestart]) { - return; - } - flags[Dirty::PrimitiveRestart] = false; - - if (maxwell3d->regs.primitive_restart.enabled) { - glEnable(GL_PRIMITIVE_RESTART); - glPrimitiveRestartIndex(maxwell3d->regs.primitive_restart.index); - } else { - glDisable(GL_PRIMITIVE_RESTART); - } -} - -void RasterizerOpenGL::SyncDepthTestState() { - auto& flags = maxwell3d->dirty.flags; - const auto& regs = maxwell3d->regs; - - if (flags[Dirty::DepthMask]) { - flags[Dirty::DepthMask] = false; - glDepthMask(regs.depth_write_enabled ? GL_TRUE : GL_FALSE); - } - - if (flags[Dirty::DepthTest]) { - flags[Dirty::DepthTest] = false; - if (regs.depth_test_enable) { - glEnable(GL_DEPTH_TEST); - glDepthFunc(MaxwellToGL::ComparisonOp(regs.depth_test_func)); - } else { - glDisable(GL_DEPTH_TEST); - } - } -} - -void RasterizerOpenGL::SyncStencilTestState() { - auto& flags = maxwell3d->dirty.flags; - if (!flags[Dirty::StencilTest]) { - return; - } - flags[Dirty::StencilTest] = false; - - const auto& regs = maxwell3d->regs; - oglEnable(GL_STENCIL_TEST, regs.stencil_enable); - - glStencilFuncSeparate(GL_FRONT, MaxwellToGL::ComparisonOp(regs.stencil_front_op.func), - regs.stencil_front_ref, regs.stencil_front_func_mask); - glStencilOpSeparate(GL_FRONT, MaxwellToGL::StencilOp(regs.stencil_front_op.fail), - MaxwellToGL::StencilOp(regs.stencil_front_op.zfail), - MaxwellToGL::StencilOp(regs.stencil_front_op.zpass)); - glStencilMaskSeparate(GL_FRONT, regs.stencil_front_mask); - - if (regs.stencil_two_side_enable) { - glStencilFuncSeparate(GL_BACK, MaxwellToGL::ComparisonOp(regs.stencil_back_op.func), - regs.stencil_back_ref, regs.stencil_back_func_mask); - glStencilOpSeparate(GL_BACK, MaxwellToGL::StencilOp(regs.stencil_back_op.fail), - MaxwellToGL::StencilOp(regs.stencil_back_op.zfail), - MaxwellToGL::StencilOp(regs.stencil_back_op.zpass)); - glStencilMaskSeparate(GL_BACK, regs.stencil_back_mask); - } else { - glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 0, 0xFFFFFFFF); - glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_KEEP); - glStencilMaskSeparate(GL_BACK, 0xFFFFFFFF); - } -} - -void RasterizerOpenGL::SyncRasterizeEnable() { - auto& flags = maxwell3d->dirty.flags; - if (!flags[Dirty::RasterizeEnable]) { - return; - } - flags[Dirty::RasterizeEnable] = false; - - oglEnable(GL_RASTERIZER_DISCARD, maxwell3d->regs.rasterize_enable == 0); -} - -void RasterizerOpenGL::SyncPolygonModes() { - auto& flags = maxwell3d->dirty.flags; - if (!flags[Dirty::PolygonModes]) { - return; - } - flags[Dirty::PolygonModes] = false; - - const auto& regs = maxwell3d->regs; - if (regs.fill_via_triangle_mode != Maxwell::FillViaTriangleMode::Disabled) { - if (!GLAD_GL_NV_fill_rectangle) { - LOG_ERROR(Render_OpenGL, "GL_NV_fill_rectangle used and not supported"); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - return; - } - - flags[Dirty::PolygonModeFront] = true; - flags[Dirty::PolygonModeBack] = true; - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL_RECTANGLE_NV); - return; - } - - if (regs.polygon_mode_front == regs.polygon_mode_back) { - flags[Dirty::PolygonModeFront] = false; - flags[Dirty::PolygonModeBack] = false; - glPolygonMode(GL_FRONT_AND_BACK, MaxwellToGL::PolygonMode(regs.polygon_mode_front)); - return; - } - - if (flags[Dirty::PolygonModeFront]) { - flags[Dirty::PolygonModeFront] = false; - glPolygonMode(GL_FRONT, MaxwellToGL::PolygonMode(regs.polygon_mode_front)); - } - - if (flags[Dirty::PolygonModeBack]) { - flags[Dirty::PolygonModeBack] = false; - glPolygonMode(GL_BACK, MaxwellToGL::PolygonMode(regs.polygon_mode_back)); - } -} - -void RasterizerOpenGL::SyncColorMask() { - auto& flags = maxwell3d->dirty.flags; - if (!flags[Dirty::ColorMasks]) { - return; - } - flags[Dirty::ColorMasks] = false; - - const bool force = flags[Dirty::ColorMaskCommon]; - flags[Dirty::ColorMaskCommon] = false; - - const auto& regs = maxwell3d->regs; - if (regs.color_mask_common) { - if (!force && !flags[Dirty::ColorMask0]) { - return; - } - flags[Dirty::ColorMask0] = false; - - auto& mask = regs.color_mask[0]; - glColorMask(mask.R != 0, mask.B != 0, mask.G != 0, mask.A != 0); - return; - } - - // Path without color_mask_common set - for (std::size_t i = 0; i < Maxwell::NumRenderTargets; ++i) { - if (!force && !flags[Dirty::ColorMask0 + i]) { - continue; - } - flags[Dirty::ColorMask0 + i] = false; - - const auto& mask = regs.color_mask[i]; - glColorMaski(static_cast(i), mask.R != 0, mask.G != 0, mask.B != 0, mask.A != 0); - } -} - -void RasterizerOpenGL::SyncMultiSampleState() { - auto& flags = maxwell3d->dirty.flags; - if (!flags[Dirty::MultisampleControl]) { - return; - } - flags[Dirty::MultisampleControl] = false; - - const auto& regs = maxwell3d->regs; - oglEnable(GL_SAMPLE_ALPHA_TO_COVERAGE, regs.anti_alias_alpha_control.alpha_to_coverage); - oglEnable(GL_SAMPLE_ALPHA_TO_ONE, regs.anti_alias_alpha_control.alpha_to_one); -} - -void RasterizerOpenGL::SyncFragmentColorClampState() { - auto& flags = maxwell3d->dirty.flags; - if (!flags[Dirty::FragmentClampColor]) { - return; - } - flags[Dirty::FragmentClampColor] = false; - - glClampColor(GL_CLAMP_FRAGMENT_COLOR, - maxwell3d->regs.frag_color_clamp.AnyEnabled() ? GL_TRUE : GL_FALSE); -} - -void RasterizerOpenGL::SyncBlendState() { - auto& flags = maxwell3d->dirty.flags; - const auto& regs = maxwell3d->regs; - - if (flags[Dirty::BlendColor]) { - flags[Dirty::BlendColor] = false; - glBlendColor(regs.blend_color.r, regs.blend_color.g, regs.blend_color.b, - regs.blend_color.a); - } - - // TODO(Rodrigo): Revisit blending, there are several registers we are not reading - - if (!flags[Dirty::BlendStates]) { - return; - } - flags[Dirty::BlendStates] = false; - - if (!regs.blend_per_target_enabled) { - if (!regs.blend.enable[0]) { - glDisable(GL_BLEND); - return; - } - glEnable(GL_BLEND); - glBlendFuncSeparate(MaxwellToGL::BlendFunc(regs.blend.color_source), - MaxwellToGL::BlendFunc(regs.blend.color_dest), - MaxwellToGL::BlendFunc(regs.blend.alpha_source), - MaxwellToGL::BlendFunc(regs.blend.alpha_dest)); - glBlendEquationSeparate(MaxwellToGL::BlendEquation(regs.blend.color_op), - MaxwellToGL::BlendEquation(regs.blend.alpha_op)); - return; - } - - const bool force = flags[Dirty::BlendIndependentEnabled]; - flags[Dirty::BlendIndependentEnabled] = false; - - for (std::size_t i = 0; i < Maxwell::NumRenderTargets; ++i) { - if (!force && !flags[Dirty::BlendState0 + i]) { - continue; - } - flags[Dirty::BlendState0 + i] = false; - - if (!regs.blend.enable[i]) { - glDisablei(GL_BLEND, static_cast(i)); - continue; - } - glEnablei(GL_BLEND, static_cast(i)); - - const auto& src = regs.blend_per_target[i]; - glBlendFuncSeparatei(static_cast(i), MaxwellToGL::BlendFunc(src.color_source), - MaxwellToGL::BlendFunc(src.color_dest), - MaxwellToGL::BlendFunc(src.alpha_source), - MaxwellToGL::BlendFunc(src.alpha_dest)); - glBlendEquationSeparatei(static_cast(i), MaxwellToGL::BlendEquation(src.color_op), - MaxwellToGL::BlendEquation(src.alpha_op)); - } -} - -void RasterizerOpenGL::SyncLogicOpState() { - auto& flags = maxwell3d->dirty.flags; - if (!flags[Dirty::LogicOp]) { - return; - } - flags[Dirty::LogicOp] = false; - - const auto& regs = maxwell3d->regs; - if (regs.logic_op.enable) { - glEnable(GL_COLOR_LOGIC_OP); - glLogicOp(MaxwellToGL::LogicOp(regs.logic_op.op)); - } else { - glDisable(GL_COLOR_LOGIC_OP); - } -} - -void RasterizerOpenGL::SyncScissorTest() { - auto& flags = maxwell3d->dirty.flags; - if (!flags[Dirty::Scissors] && !flags[VideoCommon::Dirty::RescaleScissors]) { - return; - } - flags[Dirty::Scissors] = false; - - const bool force = flags[VideoCommon::Dirty::RescaleScissors]; - flags[VideoCommon::Dirty::RescaleScissors] = false; - - const auto& regs = maxwell3d->regs; - - const auto& resolution = Settings::values.resolution_info; - const bool is_rescaling{texture_cache.IsRescaling()}; - const u32 up_scale = is_rescaling ? resolution.up_scale : 1U; - const u32 down_shift = is_rescaling ? resolution.down_shift : 0U; - const auto scale_up = [up_scale, down_shift](u32 value) -> u32 { - if (value == 0) { - return 0U; - } - const u32 upset = value * up_scale; - u32 acumm{}; - if ((up_scale >> down_shift) == 0) { - acumm = upset % 2; - } - const u32 converted_value = upset >> down_shift; - return std::max(converted_value + acumm, 1U); - }; - for (std::size_t index = 0; index < Maxwell::NumViewports; ++index) { - if (!force && !flags[Dirty::Scissor0 + index]) { - continue; - } - flags[Dirty::Scissor0 + index] = false; - - const auto& src = regs.scissor_test[index]; - if (src.enable) { - glEnablei(GL_SCISSOR_TEST, static_cast(index)); - glScissorIndexed(static_cast(index), scale_up(src.min_x), scale_up(src.min_y), - scale_up(src.max_x - src.min_x), scale_up(src.max_y - src.min_y)); - } else { - glDisablei(GL_SCISSOR_TEST, static_cast(index)); - } - } -} - -void RasterizerOpenGL::SyncPointState() { - auto& flags = maxwell3d->dirty.flags; - if (!flags[Dirty::PointSize]) { - return; - } - flags[Dirty::PointSize] = false; - - oglEnable(GL_POINT_SPRITE, maxwell3d->regs.point_sprite_enable); - oglEnable(GL_PROGRAM_POINT_SIZE, maxwell3d->regs.point_size_attribute.enabled); - const bool is_rescaling{texture_cache.IsRescaling()}; - const float scale = is_rescaling ? Settings::values.resolution_info.up_factor : 1.0f; - glPointSize(std::max(1.0f, maxwell3d->regs.point_size * scale)); -} - -void RasterizerOpenGL::SyncLineState() { - auto& flags = maxwell3d->dirty.flags; - if (!flags[Dirty::LineWidth]) { - return; - } - flags[Dirty::LineWidth] = false; - - const auto& regs = maxwell3d->regs; - oglEnable(GL_LINE_SMOOTH, regs.line_anti_alias_enable); - glLineWidth(regs.line_anti_alias_enable ? regs.line_width_smooth : regs.line_width_aliased); -} - -void RasterizerOpenGL::SyncPolygonOffset() { - auto& flags = maxwell3d->dirty.flags; - if (!flags[Dirty::PolygonOffset]) { - return; - } - flags[Dirty::PolygonOffset] = false; - - const auto& regs = maxwell3d->regs; - oglEnable(GL_POLYGON_OFFSET_FILL, regs.polygon_offset_fill_enable); - oglEnable(GL_POLYGON_OFFSET_LINE, regs.polygon_offset_line_enable); - oglEnable(GL_POLYGON_OFFSET_POINT, regs.polygon_offset_point_enable); - - if (regs.polygon_offset_fill_enable || regs.polygon_offset_line_enable || - regs.polygon_offset_point_enable) { - // Hardware divides polygon offset units by two - glPolygonOffsetClamp(regs.slope_scale_depth_bias, regs.depth_bias / 2.0f, - regs.depth_bias_clamp); - } -} - -void RasterizerOpenGL::SyncAlphaTest() { - auto& flags = maxwell3d->dirty.flags; - if (!flags[Dirty::AlphaTest]) { - return; - } - flags[Dirty::AlphaTest] = false; - - const auto& regs = maxwell3d->regs; - if (regs.alpha_test_enabled) { - glEnable(GL_ALPHA_TEST); - glAlphaFunc(MaxwellToGL::ComparisonOp(regs.alpha_test_func), regs.alpha_test_ref); - } else { - glDisable(GL_ALPHA_TEST); - } -} - -void RasterizerOpenGL::SyncFramebufferSRGB() { - auto& flags = maxwell3d->dirty.flags; - if (!flags[Dirty::FramebufferSRGB]) { - return; - } - flags[Dirty::FramebufferSRGB] = false; - - oglEnable(GL_FRAMEBUFFER_SRGB, maxwell3d->regs.framebuffer_srgb); -} - -void RasterizerOpenGL::BeginTransformFeedback(GraphicsPipeline* program, GLenum primitive_mode) { - const auto& regs = maxwell3d->regs; - if (regs.transform_feedback_enabled == 0) { - return; - } - program->ConfigureTransformFeedback(); - - UNIMPLEMENTED_IF(regs.IsShaderConfigEnabled(Maxwell::ShaderType::TessellationInit) || - regs.IsShaderConfigEnabled(Maxwell::ShaderType::Tessellation)); - - // We may have to call BeginTransformFeedbackNV here since they seem to call different - // implementations on Nvidia's driver (the pointer is different) but we are using - // ARB_transform_feedback3 features with NV_transform_feedback interactions and the ARB - // extension doesn't define BeginTransformFeedback (without NV) interactions. It just works. - glBeginTransformFeedback(primitive_mode); -} - -void RasterizerOpenGL::EndTransformFeedback() { - if (maxwell3d->regs.transform_feedback_enabled != 0) { - glEndTransformFeedback(); - } +void RasterizerOpenGL::LoadDiskResources(u64 title_id, std::stop_token stop_loading, + const VideoCore::DiskResourceLoadCallback& callback) { + shader_cache.LoadDiskResources(title_id, stop_loading, callback); } void RasterizerOpenGL::InitializeChannel(Tegra::Control::ChannelState& channel) { @@ -1394,62 +565,4 @@ void RasterizerOpenGL::RegisterTransformFeedback(GPUVAddr tfb_object_addr) { buffer_cache_runtime.BindTransformFeedbackObject(tfb_object_addr); } -AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_, TextureCache& texture_cache_) - : buffer_cache{buffer_cache_}, texture_cache{texture_cache_} {} - -bool AccelerateDMA::BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) { - std::scoped_lock lock{buffer_cache.mutex}; - return buffer_cache.DMACopy(src_address, dest_address, amount); -} - -bool AccelerateDMA::BufferClear(GPUVAddr src_address, u64 amount, u32 value) { - std::scoped_lock lock{buffer_cache.mutex}; - return buffer_cache.DMAClear(src_address, amount, value); -} - -template -bool AccelerateDMA::DmaBufferImageCopy(const Tegra::DMA::ImageCopy& copy_info, - const Tegra::DMA::BufferOperand& buffer_operand, - const Tegra::DMA::ImageOperand& image_operand) { - std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; - const auto image_id = texture_cache.DmaImageId(image_operand, IS_IMAGE_UPLOAD); - if (image_id == VideoCommon::NULL_IMAGE_ID) { - return false; - } - const u32 buffer_size = static_cast(buffer_operand.pitch * buffer_operand.height); - static constexpr auto sync_info = VideoCommon::ObtainBufferSynchronize::FullSynchronize; - const auto post_op = IS_IMAGE_UPLOAD ? VideoCommon::ObtainBufferOperation::DoNothing - : VideoCommon::ObtainBufferOperation::MarkAsWritten; - const auto [buffer, offset] = - buffer_cache.ObtainBuffer(buffer_operand.address, buffer_size, sync_info, post_op); - - const auto [image, copy] = texture_cache.DmaBufferImageCopy( - copy_info, buffer_operand, image_operand, image_id, IS_IMAGE_UPLOAD); - const std::span copy_span{©, 1}; - - if constexpr (IS_IMAGE_UPLOAD) { - texture_cache.PrepareImage(image_id, true, false); - image->UploadMemory(buffer->Handle(), offset, copy_span); - } else { - if (offset % BytesPerBlock(image->info.format)) { - return false; - } - texture_cache.DownloadImageIntoBuffer(image, buffer->Handle(), offset, copy_span, - buffer_operand.address, buffer_size); - } - return true; -} - -bool AccelerateDMA::ImageToBuffer(const Tegra::DMA::ImageCopy& copy_info, - const Tegra::DMA::ImageOperand& image_operand, - const Tegra::DMA::BufferOperand& buffer_operand) { - return DmaBufferImageCopy(copy_info, buffer_operand, image_operand); -} - -bool AccelerateDMA::BufferToImage(const Tegra::DMA::ImageCopy& copy_info, - const Tegra::DMA::BufferOperand& buffer_operand, - const Tegra::DMA::ImageOperand& image_operand) { - return DmaBufferImageCopy(copy_info, buffer_operand, image_operand); -} - } // namespace OpenGL