diff --git a/src/core/gpu_hw.cpp b/src/core/gpu_hw.cpp index d44e512854..f471eb34dd 100644 --- a/src/core/gpu_hw.cpp +++ b/src/core/gpu_hw.cpp @@ -645,10 +645,15 @@ bool GPU_HW::CreateBuffers() GL_OBJECT_NAME(m_vram_read_texture, "VRAM Read Texture"); GL_OBJECT_NAME(m_vram_readback_texture, "VRAM Readback Texture"); - if (!(m_vram_upload_buffer = - g_gpu_device->CreateTextureBuffer(GPUTextureBuffer::Format::R16UI, GPUDevice::MIN_TEXEL_BUFFER_ELEMENTS))) + if (g_gpu_device->GetFeatures().supports_texture_buffers) { - return false; + if (!(m_vram_upload_buffer = + g_gpu_device->CreateTextureBuffer(GPUTextureBuffer::Format::R16UI, GPUDevice::MIN_TEXEL_BUFFER_ELEMENTS))) + { + return false; + } + + GL_OBJECT_NAME(m_vram_upload_buffer, "VRAM Upload Buffer"); } Log_InfoFmt("Created HW framebuffer of {}x{}", texture_width, texture_height); @@ -999,9 +1004,10 @@ bool GPU_HW::CompilePipelines() // VRAM write { + const bool use_buffer = features.supports_texture_buffers; const bool use_ssbo = features.texture_buffers_emulated_with_ssbo; - std::unique_ptr fs = - g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GenerateVRAMWriteFragmentShader(use_ssbo)); + std::unique_ptr fs = g_gpu_device->CreateShader( + GPUShaderStage::Fragment, shadergen.GenerateVRAMWriteFragmentShader(use_buffer, use_ssbo)); if (!fs) return false; @@ -2438,11 +2444,28 @@ void GPU_HW::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data, b } } - const u32 num_pixels = width * height; - void* map = m_vram_upload_buffer->Map(num_pixels); - const u32 map_index = m_vram_upload_buffer->GetCurrentPosition(); - std::memcpy(map, data, num_pixels * sizeof(u16)); - m_vram_upload_buffer->Unmap(num_pixels); + std::unique_ptr upload_texture; + u32 map_index; + + if (!g_gpu_device->GetFeatures().supports_texture_buffers) + { + map_index = 0; + upload_texture = g_gpu_device->FetchTexture(width, height, 1, 1, 1, GPUTexture::Type::Texture, + GPUTexture::Format::R16U, data, width * sizeof(u16)); + if (!upload_texture) + { + Log_ErrorFmt("Failed to get {}x{} upload texture. Things are gonna break.", width, height); + return; + } + } + else + { + const u32 num_pixels = width * height; + void* map = m_vram_upload_buffer->Map(num_pixels); + map_index = m_vram_upload_buffer->GetCurrentPosition(); + std::memcpy(map, data, num_pixels * sizeof(u16)); + m_vram_upload_buffer->Unmap(num_pixels); + } struct VRAMWriteUBOData { @@ -2465,8 +2488,17 @@ void GPU_HW::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data, b g_gpu_device->SetScissor(scaled_bounds.left, scaled_bounds.top, scaled_bounds.GetWidth(), scaled_bounds.GetHeight()); g_gpu_device->SetPipeline(m_vram_write_pipelines[BoolToUInt8(check_mask && !m_pgxp_depth_buffer)].get()); g_gpu_device->PushUniformBuffer(&uniforms, sizeof(uniforms)); - g_gpu_device->SetTextureBuffer(0, m_vram_upload_buffer.get()); - g_gpu_device->Draw(3, 0); + if (upload_texture) + { + g_gpu_device->SetTextureSampler(0, upload_texture.get(), g_gpu_device->GetNearestSampler()); + g_gpu_device->Draw(3, 0); + g_gpu_device->RecycleTexture(std::move(upload_texture)); + } + else + { + g_gpu_device->SetTextureBuffer(0, m_vram_upload_buffer.get()); + g_gpu_device->Draw(3, 0); + } RestoreDeviceContext(); } diff --git a/src/core/gpu_hw_shadergen.cpp b/src/core/gpu_hw_shadergen.cpp index 06c117ab98..32483a85b4 100644 --- a/src/core/gpu_hw_shadergen.cpp +++ b/src/core/gpu_hw_shadergen.cpp @@ -1271,18 +1271,23 @@ uint SampleVRAM(uint2 coords) return ss.str(); } -std::string GPU_HW_ShaderGen::GenerateVRAMWriteFragmentShader(bool use_ssbo) +std::string GPU_HW_ShaderGen::GenerateVRAMWriteFragmentShader(bool use_buffer, bool use_ssbo) { std::stringstream ss; WriteHeader(ss); WriteCommonFunctions(ss); DefineMacro(ss, "PGXP_DEPTH", m_pgxp_depth); + DefineMacro(ss, "USE_BUFFER", use_buffer); DeclareUniformBuffer(ss, {"uint2 u_base_coords", "uint2 u_end_coords", "uint2 u_size", "uint u_buffer_base_offset", "uint u_mask_or_bits", "float u_depth_value"}, true); - if (use_ssbo && m_glsl) + if (!use_buffer) + { + DeclareTexture(ss, "samp0", 0, false, true, true); + } + else if (use_ssbo && m_glsl) { ss << "layout(std430"; if (IsVulkan()) @@ -1316,14 +1321,17 @@ std::string GPU_HW_ShaderGen::GenerateVRAMWriteFragmentShader(bool use_ssbo) discard; } - // find offset from the start of the row/column uint2 offset; offset.x = (coords.x < u_base_coords.x) ? ((VRAM_SIZE.x / RESOLUTION_SCALE) - u_base_coords.x + coords.x) : (coords.x - u_base_coords.x); offset.y = (coords.y < u_base_coords.y) ? ((VRAM_SIZE.y / RESOLUTION_SCALE) - u_base_coords.y + coords.y) : (coords.y - u_base_coords.y); +#if !USE_BUFFER + uint value = LOAD_TEXTURE(samp0, int2(offset), 0).x; +#else uint buffer_offset = u_buffer_base_offset + (offset.y * u_size.x) + offset.x; uint value = GET_VALUE(buffer_offset) | u_mask_or_bits; +#endif o_col0 = RGBA5551ToRGBA8(value); #if !PGXP_DEPTH diff --git a/src/core/gpu_hw_shadergen.h b/src/core/gpu_hw_shadergen.h index cda16ce221..576550c722 100644 --- a/src/core/gpu_hw_shadergen.h +++ b/src/core/gpu_hw_shadergen.h @@ -22,7 +22,7 @@ class GPU_HW_ShaderGen : public ShaderGen std::string GenerateWireframeGeometryShader(); std::string GenerateWireframeFragmentShader(); std::string GenerateVRAMReadFragmentShader(); - std::string GenerateVRAMWriteFragmentShader(bool use_ssbo); + std::string GenerateVRAMWriteFragmentShader(bool use_buffer, bool use_ssbo); std::string GenerateVRAMCopyFragmentShader(); std::string GenerateVRAMFillFragmentShader(bool wrapped, bool interlaced); std::string GenerateVRAMUpdateDepthFragmentShader(); diff --git a/src/util/opengl_device.cpp b/src/util/opengl_device.cpp index 56827b2c6e..da8f52cc18 100644 --- a/src/util/opengl_device.cpp +++ b/src/util/opengl_device.cpp @@ -492,10 +492,7 @@ bool OpenGLDevice::CheckFeatures(bool* buggy_pbo, FeatureMask disabled_features) } else { - Host::ReportErrorAsync( - TRANSLATE_SV("GPUDevice", "Error"), - TRANSLATE_SV("Error", "Both texture buffers and SSBOs are not supported, or are of inadequate size.")); - return false; + Log_WarningPrint("Both texture buffers and SSBOs are not supported. Performance will suffer."); } }