gl: Improve pixel transfer code and notify on AMD driver bug

- Readback does not work at all with float textures on AMD openGL
  Driver throws a bogus OUT_OF_MEMORY error regardless of amount of VRAM and system RAM available
This commit is contained in:
kd-11 2018-04-23 16:13:00 +03:00 committed by kd-11
parent f3210a9a33
commit ffa62918aa
2 changed files with 20 additions and 39 deletions

View File

@ -1318,7 +1318,7 @@ void GLGSRender::flip(int buffer)
u32 buffer_height = display_buffers[buffer].height;
u32 buffer_pitch = display_buffers[buffer].pitch;
if ((u32)buffer < display_buffers_count && buffer_width && buffer_height)
if ((u32)buffer < display_buffers_count && buffer_width && buffer_height && buffer_pitch)
{
// Calculate blit coordinates
coordi aspect_ratio;
@ -1362,13 +1362,7 @@ void GLGSRender::flip(int buffer)
{
//Hack - this should be the first location to check for output
//The render might have been done offscreen or in software and a blit used to display
image = surface->get_raw_view()->id();
//Reset color swizzle
glBindTexture(GL_TEXTURE_2D, image);
const GLenum rgba_shuffle[] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA };
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, (GLint*)rgba_shuffle);
surface->set_sampler_status(rsx::texture_sampler_status::status_uninitialized);
image = surface->get_raw_texture()->id();
}
else
{

View File

@ -225,6 +225,7 @@ namespace gl
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_id);
glBufferStorage(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_MAP_READ_BIT);
glBindBuffer(GL_PIXEL_PACK_BUFFER, GL_NONE);
pbo_size = buffer_size;
}
@ -350,7 +351,7 @@ namespace gl
init_buffer();
}
u32 target_texture = vram_texture->id();
gl::texture* target_texture = vram_texture;
if ((rsx::get_resolution_scale_percent() != 100 && context == rsx::texture_upload_context::framebuffer_storage) ||
(real_pitch != rsx_pitch))
{
@ -398,47 +399,33 @@ namespace gl
bool linear_interp = false; //TODO: Make optional or detect full sized sources
g_hw_blitter->scale_image(vram_texture, scaled_texture.get(), src_area, dst_area, linear_interp, is_depth, {});
target_texture = scaled_texture->id();
target_texture = scaled_texture.get();
}
}
glPixelStorei(GL_PACK_SWAP_BYTES, pack_unpack_swap_bytes);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_id);
glGetError();
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_id);
if (get_driver_caps().EXT_dsa_supported)
glGetTextureImageEXT(target_texture, GL_TEXTURE_2D, 0, (GLenum)format, (GLenum)type, nullptr);
else
glGetTextureImage(target_texture, 0, (GLenum)format, (GLenum)type, pbo_size, nullptr);
pixel_pack_settings pack_settings;
pack_settings.aligment(1).swap_bytes(pack_unpack_swap_bytes);
target_texture->copy_to(nullptr, format, type, pack_settings);
if (GLenum err = glGetError())
if (auto error = glGetError())
{
bool recovered = false;
if (scaled_texture && (target_texture == scaled_texture->id()))
if (error == GL_OUT_OF_MEMORY && ::gl::get_driver_caps().vendor_AMD)
{
if (get_driver_caps().EXT_dsa_supported)
glGetTextureImageEXT(vram_texture->id(), GL_TEXTURE_2D, 0, (GLenum)format, (GLenum)type, nullptr);
else
glGetTextureImage(vram_texture->id(), 0, (GLenum)format, (GLenum)type, pbo_size, nullptr);
if (!glGetError())
{
recovered = true;
const u32 min_dimension = cpu_address_range / rsx_pitch;
LOG_WARNING(RSX, "Failed to read back a scaled image, but the original texture can be read back. Consider setting min scalable dimension below or equal to %d", min_dimension);
}
//AMD driver bug
//Pixel transfer fails with GL_OUT_OF_MEMORY. Usually happens with float textures
//Failed operations also leak a large amount of memory
LOG_ERROR(RSX, "Memory transfer failure (AMD bug). Format=0x%x, Type=0x%x", (u32)format, (u32)type);
}
if (!recovered && rsx::get_resolution_scale_percent() != 100 && context == rsx::texture_upload_context::framebuffer_storage)
else
{
LOG_ERROR(RSX, "Texture readback failed. Disable resolution scaling to get the 'Write Color Buffers' option to work properly");
LOG_ERROR(RSX, "Memory transfer failed with error 0x%x. Format=0x%x, Type=0x%x", error, (u32)format, (u32)type);
}
}
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
glBindBuffer(GL_PIXEL_PACK_BUFFER, GL_NONE);
m_fence.reset();
synchronized = true;
@ -459,7 +446,7 @@ namespace gl
glPixelStorei(GL_UNPACK_SWAP_BYTES, pack_unpack_swap_bytes);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_id);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, min_width, min_height, (GLenum)format, (GLenum)type, nullptr);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, GL_NONE);
}
bool flush()
@ -518,7 +505,7 @@ namespace gl
}
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
glBindBuffer(GL_PIXEL_PACK_BUFFER, GL_NONE);
reset_write_statistics();