rasterizer_cache: Improve TextureRuntime API

* This makes every operation more explicit and mimics more the Vulkan API
This commit is contained in:
emufan4568
2022-09-09 00:42:14 +03:00
committed by GPUCode
parent e30e977140
commit 68ca206d53
5 changed files with 248 additions and 162 deletions

View File

@ -337,17 +337,21 @@ void CachedSurface::UploadGLTexture(Common::Rectangle<u32> rect) {
const Common::Rectangle<u32> from_rect{0, height, width, 0}; const Common::Rectangle<u32> from_rect{0, height, width, 0};
if (is_custom || !owner.texture_filterer->Filter(unscaled_tex, from_rect, texture, scaled_rect, type)) { if (is_custom || !owner.texture_filterer->Filter(unscaled_tex, from_rect, texture, scaled_rect, type)) {
const Subresource src_subresource = { const TextureBlit texture_blit = {
.type = type, .surface_type = type,
.region = from_rect .src_level = 0,
.dst_level = 0,
.src_region = Region2D{
.start = {0, 0},
.end = {width, height}
},
.dst_region = Region2D{
.start = {rect.left, rect.bottom},
.end = {rect.right, rect.top}
}
}; };
const Subresource dst_subresource = { runtime.BlitTextures(unscaled_tex, texture, texture_blit);
.type = type,
.region = scaled_rect
};
runtime.BlitTextures(unscaled_tex, src_subresource, texture, dst_subresource);
} }
} }
@ -363,8 +367,10 @@ void CachedSurface::DownloadGLTexture(const Common::Rectangle<u32>& rect) {
MICROPROFILE_SCOPE(RasterizerCache_TextureDL); MICROPROFILE_SCOPE(RasterizerCache_TextureDL);
const u32 download_size = width * height * GetBytesPerPixel(pixel_format);
if (gl_buffer.empty()) { if (gl_buffer.empty()) {
gl_buffer.resize(width * height * GetBytesPerPixel(pixel_format)); gl_buffer.resize(download_size);
} }
OpenGLState state = OpenGLState::GetCurState(); OpenGLState state = OpenGLState::GetCurState();
@ -374,10 +380,7 @@ void CachedSurface::DownloadGLTexture(const Common::Rectangle<u32>& rect) {
// Ensure no bad interactions with GL_PACK_ALIGNMENT // Ensure no bad interactions with GL_PACK_ALIGNMENT
ASSERT(stride * GetBytesPerPixel(pixel_format) % 4 == 0); ASSERT(stride * GetBytesPerPixel(pixel_format) % 4 == 0);
glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(stride)); glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(stride));
const std::size_t buffer_offset = const u32 buffer_offset = (rect.bottom * stride + rect.left) * GetBytesPerPixel(pixel_format);
(rect.bottom * stride + rect.left) * GetBytesPerPixel(pixel_format);
const FormatTuple& tuple = GetFormatTuple(pixel_format);
// If not 1x scale, blit scaled texture to a new 1x texture and use that to flush // If not 1x scale, blit scaled texture to a new 1x texture and use that to flush
if (res_scale != 1) { if (res_scale != 1) {
@ -390,23 +393,29 @@ void CachedSurface::DownloadGLTexture(const Common::Rectangle<u32>& rect) {
const Common::Rectangle<u32> unscaled_tex_rect{0, rect.GetHeight(), rect.GetWidth(), 0}; const Common::Rectangle<u32> unscaled_tex_rect{0, rect.GetHeight(), rect.GetWidth(), 0};
auto unscaled_tex = owner.AllocateSurfaceTexture(pixel_format, rect.GetWidth(), rect.GetHeight()); auto unscaled_tex = owner.AllocateSurfaceTexture(pixel_format, rect.GetWidth(), rect.GetHeight());
const Subresource src_subresource = { const TextureBlit texture_blit = {
.type = type, .surface_type = type,
.region = scaled_rect .src_level = 0,
}; .dst_level = 0,
.src_region = Region2D{
const Subresource dst_subresource = { .start = {scaled_rect.left, scaled_rect.bottom},
.type = type, .end = {scaled_rect.right, scaled_rect.top}
.region = unscaled_tex_rect },
.dst_region = Region2D{
.start = {unscaled_tex_rect.left, unscaled_tex_rect.bottom},
.end = {unscaled_tex_rect.right, unscaled_tex_rect.top}
}
}; };
// Blit scaled texture to the unscaled one // Blit scaled texture to the unscaled one
runtime.BlitTextures(texture, src_subresource, unscaled_tex, dst_subresource); runtime.BlitTextures(texture, unscaled_tex, texture_blit);
state.texture_units[0].texture_2d = unscaled_tex.handle; state.texture_units[0].texture_2d = unscaled_tex.handle;
state.Apply(); state.Apply();
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
const FormatTuple& tuple = GetFormatTuple(pixel_format);
if (GLES) { if (GLES) {
owner.texture_downloader_es->GetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, owner.texture_downloader_es->GetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type,
rect.GetHeight(), rect.GetWidth(), rect.GetHeight(), rect.GetWidth(),
@ -415,12 +424,18 @@ void CachedSurface::DownloadGLTexture(const Common::Rectangle<u32>& rect) {
glGetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, &gl_buffer[buffer_offset]); glGetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, &gl_buffer[buffer_offset]);
} }
} else { } else {
const Subresource subresource = { const BufferTextureCopy texture_download = {
.type = type, .buffer_offset = buffer_offset,
.region = rect .buffer_size = download_size,
.buffer_row_length = stride,
.buffer_height = height,
.surface_type = type,
.texture_level = 0,
.texture_offset = {rect.bottom, rect.left},
.texture_extent = {rect.GetWidth(), rect.GetHeight()}
}; };
runtime.ReadTexture(texture, subresource, tuple, (u8*)gl_buffer.data()); runtime.ReadTexture(texture, texture_download, pixel_format, gl_buffer);
} }
glPixelStorei(GL_PACK_ROW_LENGTH, 0); glPixelStorei(GL_PACK_ROW_LENGTH, 0);

View File

@ -49,11 +49,7 @@ void RasterizerCache::CopySurface(const Surface& src_surface, const Surface& dst
SurfaceParams subrect_params = dst_surface->FromInterval(copy_interval); SurfaceParams subrect_params = dst_surface->FromInterval(copy_interval);
ASSERT(subrect_params.GetInterval() == copy_interval && src_surface != dst_surface); ASSERT(subrect_params.GetInterval() == copy_interval && src_surface != dst_surface);
const Subresource dst_subresource = { const auto dst_rect = dst_surface->GetScaledSubRect(subrect_params);
.type = dst_surface->type,
.region = dst_surface->GetScaledSubRect(subrect_params)
};
if (src_surface->type == SurfaceType::Fill) { if (src_surface->type == SurfaceType::Fill) {
// FillSurface needs a 4 bytes buffer // FillSurface needs a 4 bytes buffer
const u32 fill_offset = const u32 fill_offset =
@ -68,18 +64,36 @@ void RasterizerCache::CopySurface(const Surface& src_surface, const Surface& dst
const ClearValue clear_value = const ClearValue clear_value =
MakeClearValue(dst_surface->type, dst_surface->pixel_format, fill_buffer.data()); MakeClearValue(dst_surface->type, dst_surface->pixel_format, fill_buffer.data());
runtime.ClearTexture(dst_surface->texture, dst_subresource, clear_value); const ClearRect clear_rect = {
.surface_type = dst_surface->type,
.texture_level = 0,
.rect = Rect2D{
.offset = {dst_rect.left, dst_rect.bottom},
.extent = {dst_rect.GetWidth(), dst_rect.GetHeight()}
}
};
runtime.ClearTexture(dst_surface->texture, clear_rect, clear_value);
return; return;
} }
if (src_surface->CanSubRect(subrect_params)) { if (src_surface->CanSubRect(subrect_params)) {
const Subresource src_subresource = { const auto src_rect = src_surface->GetScaledSubRect(subrect_params);
.type = src_surface->type, const TextureBlit texture_blit = {
.region = src_surface->GetScaledSubRect(subrect_params) .surface_type = src_surface->type,
.src_level = 0,
.dst_level = 0,
.src_region = Region2D{
.start = {src_rect.left, src_rect.bottom},
.end = {src_rect.right, src_rect.top}
},
.dst_region = Region2D{
.start = {dst_rect.left, dst_rect.bottom},
.end = {dst_rect.right, dst_rect.top}
}
}; };
runtime.BlitTextures(src_surface->texture, src_subresource, dst_surface->texture, runtime.BlitTextures(src_surface->texture, dst_surface->texture, texture_blit);
dst_subresource);
return; return;
} }
@ -210,18 +224,21 @@ bool RasterizerCache::BlitSurfaces(const Surface& src_surface,
if (CheckFormatsBlittable(src_surface->pixel_format, dst_surface->pixel_format)) { if (CheckFormatsBlittable(src_surface->pixel_format, dst_surface->pixel_format)) {
dst_surface->InvalidateAllWatcher(); dst_surface->InvalidateAllWatcher();
const Subresource src_subresource = { const TextureBlit texture_blit = {
.type = src_surface->type, .surface_type = src_surface->type,
.region = src_rect .src_level = 0,
.dst_level = 0,
.src_region = Region2D{
.start = {src_rect.left, src_rect.bottom},
.end = {src_rect.right, src_rect.top}
},
.dst_region = Region2D{
.start = {dst_rect.left, dst_rect.bottom},
.end = {dst_rect.right, dst_rect.top}
}
}; };
const Subresource dst_subresource = { return runtime.BlitTextures(src_surface->texture, dst_surface->texture, texture_blit);
.type = dst_surface->type,
.region = dst_rect
};
return runtime.BlitTextures(src_surface->texture, src_subresource,
dst_surface->texture, dst_subresource);
} }
return false; return false;
@ -441,19 +458,23 @@ Surface RasterizerCache::GetTextureSurface(const Pica::Texture::TextureInfo& inf
} }
if (!surface->is_custom && texture_filterer->IsNull()) { if (!surface->is_custom && texture_filterer->IsNull()) {
const Subresource src_subresource = { const auto src_rect = level_surface->GetScaledRect();
.type = surface->type, const auto dst_rect = surface_params.GetScaledRect();
.region = level_surface->GetScaledRect() const TextureBlit texture_blit = {
.surface_type = surface->type,
.src_level = 0,
.dst_level = level,
.src_region = Region2D{
.start = {src_rect.left, src_rect.bottom},
.end = {src_rect.right, src_rect.top}
},
.dst_region = Region2D{
.start = {dst_rect.left, dst_rect.bottom},
.end = {dst_rect.right, dst_rect.top}
}
}; };
const Subresource dst_subresource = { runtime.BlitTextures(level_surface->texture, surface->texture, texture_blit);
.type = surface->type,
.region = surface_params.GetScaledRect(),
.level = level
};
runtime.BlitTextures(level_surface->texture, src_subresource,
surface->texture, dst_subresource);
} }
watcher->Validate(); watcher->Validate();
@ -530,19 +551,22 @@ const CachedTextureCube& RasterizerCache::GetTextureCube(const TextureCubeConfig
ValidateSurface(surface, surface->addr, surface->size); ValidateSurface(surface, surface->addr, surface->size);
} }
const Subresource src_subresource = { const auto src_rect = surface->GetScaledRect();
.type = surface->type, const TextureBlit texture_blit = {
.region = surface->GetScaledRect() .surface_type = surface->type,
.src_level = 0,
.dst_level = 0,
.src_region = Region2D{
.start = {src_rect.left, src_rect.bottom},
.end = {src_rect.right, src_rect.top}
},
.dst_region = Region2D{
.start = {0, 0},
.end = {scaled_size, scaled_size}
}
}; };
const Subresource dst_subresource = { runtime.BlitTextures(surface->texture, cube.texture, texture_blit);
.type = surface->type,
.region = Common::Rectangle<u32>{0, scaled_size, scaled_size, 0}
};
runtime.BlitTextures(surface->texture, src_subresource,
cube.texture, dst_subresource);
face.watcher->Validate(); face.watcher->Validate();
} }
} }
@ -857,22 +881,24 @@ bool RasterizerCache::ValidateByReinterpretation(const Surface& surface,
reinterpreter->Reinterpret(reinterpret_surface->texture, src_rect, tmp_tex, reinterpreter->Reinterpret(reinterpret_surface->texture, src_rect, tmp_tex,
tmp_rect); tmp_rect);
if (!texture_filterer->Filter(tmp_tex, tmp_rect, surface->texture, dest_rect, if (!texture_filterer->Filter(tmp_tex, tmp_rect, surface->texture, dest_rect, type)) {
type)) { const TextureBlit texture_blit = {
.surface_type = type,
const Subresource src_subresource = { .src_level = 0,
.type = type, .dst_level = 0,
.region = tmp_rect .src_region = Region2D{
.start = {0, 0},
.end = {width, height}
},
.dst_region = Region2D{
.start = {dest_rect.left, dest_rect.bottom},
.end = {dest_rect.right, dest_rect.top}
}
}; };
const Subresource dst_subresource = { runtime.BlitTextures(tmp_tex, surface->texture, texture_blit);
.type = type,
.region = dest_rect
};
runtime.BlitTextures(tmp_tex, src_subresource,
surface->texture, dst_subresource);
} }
} else { } else {
reinterpreter->Reinterpret(reinterpret_surface->texture, src_rect, surface->texture, reinterpreter->Reinterpret(reinterpret_surface->texture, src_rect, surface->texture,
dest_rect); dest_rect);

View File

@ -31,70 +31,69 @@ TextureRuntime::TextureRuntime() {
draw_fbo.Create(); draw_fbo.Create();
} }
void TextureRuntime::ReadTexture(const OGLTexture& tex, Subresource subresource, void TextureRuntime::ReadTexture(OGLTexture& texture, const BufferTextureCopy& copy,
const FormatTuple& tuple, u8* pixels) { PixelFormat format, std::span<std::byte> pixels) {
OpenGLState prev_state = OpenGLState::GetCurState(); OpenGLState prev_state = OpenGLState::GetCurState();
SCOPE_EXIT({ prev_state.Apply(); }); SCOPE_EXIT({ prev_state.Apply(); });
OpenGLState state; OpenGLState state{};
state.ResetTexture(tex.handle); state.ResetTexture(texture.handle);
state.draw.read_framebuffer = read_fbo.handle; state.draw.read_framebuffer = read_fbo.handle;
state.Apply(); state.Apply();
const u32 level = subresource.level; switch (copy.surface_type) {
switch (subresource.type) {
case SurfaceType::Color: case SurfaceType::Color:
case SurfaceType::Texture: case SurfaceType::Texture:
case SurfaceType::Fill: case SurfaceType::Fill:
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex.handle, glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.handle,
level); copy.texture_level);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
0); 0);
break; break;
case SurfaceType::Depth: case SurfaceType::Depth:
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, tex.handle, glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texture.handle,
level); copy.texture_level);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
break; break;
case SurfaceType::DepthStencil: case SurfaceType::DepthStencil:
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
tex.handle, level); texture.handle, copy.texture_level);
break; break;
default: default:
UNREACHABLE_MSG("Invalid surface type!"); UNREACHABLE_MSG("Invalid surface type!");
} }
const auto& rect = subresource.region; // TODO: Use PBO here
glReadPixels(rect.left, rect.bottom, rect.GetWidth(), rect.GetHeight(), tuple.format, const FormatTuple& tuple = GetFormatTuple(format);
tuple.type, pixels); glReadPixels(copy.texture_offset.x, copy.texture_offset.y,
copy.texture_offset.x + copy.texture_extent.width,
copy.texture_offset.y + copy.texture_extent.height,
tuple.format, tuple.type, pixels.data() + copy.buffer_offset);
} }
bool TextureRuntime::ClearTexture(const OGLTexture& tex, Subresource subresource, bool TextureRuntime::ClearTexture(OGLTexture& texture, const ClearRect& rect, ClearValue value) {
ClearValue value) {
OpenGLState prev_state = OpenGLState::GetCurState(); OpenGLState prev_state = OpenGLState::GetCurState();
SCOPE_EXIT({ prev_state.Apply(); }); SCOPE_EXIT({ prev_state.Apply(); });
// Setup scissor rectangle according to the clear rectangle // Setup scissor rectangle according to the clear rectangle
const auto& clear_rect = subresource.region; OpenGLState state{};
OpenGLState state;
state.scissor.enabled = true; state.scissor.enabled = true;
state.scissor.x = clear_rect.left; state.scissor.x = rect.rect.offset.x;
state.scissor.y = clear_rect.bottom; state.scissor.y = rect.rect.offset.y;
state.scissor.width = clear_rect.GetWidth(); state.scissor.width = rect.rect.extent.width;
state.scissor.height = clear_rect.GetHeight(); state.scissor.height = rect.rect.extent.height;
state.draw.draw_framebuffer = draw_fbo.handle; state.draw.draw_framebuffer = draw_fbo.handle;
state.Apply(); state.Apply();
const u32 level = subresource.level; switch (rect.surface_type) {
switch (subresource.type) {
case SurfaceType::Color: case SurfaceType::Color:
case SurfaceType::Texture: case SurfaceType::Texture:
case SurfaceType::Fill: case SurfaceType::Fill:
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex.handle, glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.handle,
level); rect.texture_level);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
0); 0);
@ -108,8 +107,8 @@ bool TextureRuntime::ClearTexture(const OGLTexture& tex, Subresource subresource
break; break;
case SurfaceType::Depth: case SurfaceType::Depth:
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, tex.handle, glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texture.handle,
level); rect.texture_level);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
state.depth.write_mask = GL_TRUE; state.depth.write_mask = GL_TRUE;
@ -120,7 +119,7 @@ bool TextureRuntime::ClearTexture(const OGLTexture& tex, Subresource subresource
case SurfaceType::DepthStencil: case SurfaceType::DepthStencil:
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
tex.handle, level); texture.handle, rect.texture_level);
state.depth.write_mask = GL_TRUE; state.depth.write_mask = GL_TRUE;
state.stencil.write_mask = -1; state.stencil.write_mask = -1;
@ -135,50 +134,42 @@ bool TextureRuntime::ClearTexture(const OGLTexture& tex, Subresource subresource
return true; return true;
} }
bool TextureRuntime::CopyTextures(const OGLTexture& src_tex, Subresource src_subresource, bool TextureRuntime::CopyTextures(OGLTexture& source, OGLTexture& dest, const TextureCopy& copy) {
const OGLTexture& dst_tex, Subresource dst_subresource) {
return true; return true;
} }
bool TextureRuntime::BlitTextures(const OGLTexture& src_tex, Subresource src_subresource, bool TextureRuntime::BlitTextures(OGLTexture& source, OGLTexture& dest, const TextureBlit& blit) {
const OGLTexture& dst_tex, Subresource dst_subresource,
bool dst_cube) {
OpenGLState prev_state = OpenGLState::GetCurState(); OpenGLState prev_state = OpenGLState::GetCurState();
SCOPE_EXIT({ prev_state.Apply(); }); SCOPE_EXIT({ prev_state.Apply(); });
OpenGLState state; OpenGLState state{};
state.draw.read_framebuffer = read_fbo.handle; state.draw.read_framebuffer = read_fbo.handle;
state.draw.draw_framebuffer = draw_fbo.handle; state.draw.draw_framebuffer = draw_fbo.handle;
state.Apply(); state.Apply();
auto BindAttachment = auto BindAttachment = [&blit](GLenum target, u32 src_tex, u32 dst_tex) -> void {
[dst_cube, src_level = src_subresource.level, dst_level = dst_subresource.level, glFramebufferTexture2D(GL_READ_FRAMEBUFFER, target, GL_TEXTURE_2D, src_tex, blit.src_level);
dst_layer = dst_subresource.layer](GLenum target, u32 src_tex, u32 dst_tex) -> void { glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, target, GL_TEXTURE_2D, dst_tex, blit.dst_level);
GLenum dst_target = dst_cube ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + dst_layer : GL_TEXTURE_2D;
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, target, GL_TEXTURE_2D, src_tex, src_level);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, target, dst_target, dst_tex, dst_level);
}; };
// Sanity check; Can't blit a color texture to a depth buffer switch (blit.surface_type) {
ASSERT(src_subresource.type == dst_subresource.type);
switch (src_subresource.type) {
case SurfaceType::Color: case SurfaceType::Color:
case SurfaceType::Texture: case SurfaceType::Texture:
case SurfaceType::Fill: case SurfaceType::Fill:
// Bind only color // Bind only color
BindAttachment(GL_COLOR_ATTACHMENT0, src_tex.handle, dst_tex.handle); BindAttachment(GL_COLOR_ATTACHMENT0, source.handle, dest.handle);
BindAttachment(GL_DEPTH_STENCIL_ATTACHMENT, 0, 0); BindAttachment(GL_DEPTH_STENCIL_ATTACHMENT, 0, 0);
break; break;
case SurfaceType::Depth: case SurfaceType::Depth:
// Bind only depth // Bind only depth
BindAttachment(GL_COLOR_ATTACHMENT0, 0, 0); BindAttachment(GL_COLOR_ATTACHMENT0, 0, 0);
BindAttachment(GL_DEPTH_ATTACHMENT, src_tex.handle, dst_tex.handle); BindAttachment(GL_DEPTH_ATTACHMENT, source.handle, dest.handle);
BindAttachment(GL_STENCIL_ATTACHMENT, 0, 0); BindAttachment(GL_STENCIL_ATTACHMENT, 0, 0);
break; break;
case SurfaceType::DepthStencil: case SurfaceType::DepthStencil:
// Bind to combined depth + stencil // Bind to combined depth + stencil
BindAttachment(GL_COLOR_ATTACHMENT0, 0, 0); BindAttachment(GL_COLOR_ATTACHMENT0, 0, 0);
BindAttachment(GL_DEPTH_STENCIL_ATTACHMENT, src_tex.handle, dst_tex.handle); BindAttachment(GL_DEPTH_STENCIL_ATTACHMENT, source.handle, dest.handle);
break; break;
default: default:
UNREACHABLE_MSG("Invalid surface type!"); UNREACHABLE_MSG("Invalid surface type!");
@ -189,23 +180,23 @@ bool TextureRuntime::BlitTextures(const OGLTexture& src_tex, Subresource src_sub
// doing linear intepolation componentwise would cause incorrect value. However, for a // doing linear intepolation componentwise would cause incorrect value. However, for a
// well-programmed game this code path should be rarely executed for shadow map with // well-programmed game this code path should be rarely executed for shadow map with
// inconsistent scale. // inconsistent scale.
const GLbitfield buffer_mask = MakeBufferMask(src_subresource.type); const GLbitfield buffer_mask = MakeBufferMask(blit.surface_type);
const GLenum filter = buffer_mask == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST; const GLenum filter = buffer_mask == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST;
const auto& src_rect = src_subresource.region; glBlitFramebuffer(blit.src_region.start.x, blit.src_region.start.y,
const auto& dst_rect = dst_subresource.region; blit.src_region.end.x, blit.src_region.end.y,
glBlitFramebuffer(src_rect.left, src_rect.bottom, src_rect.right, src_rect.top, dst_rect.left, blit.dst_region.start.x, blit.dst_region.start.y,
dst_rect.bottom, dst_rect.right, dst_rect.top, blit.dst_region.end.x, blit.dst_region.end.y,
buffer_mask, filter); buffer_mask, filter);
return true; return true;
} }
void TextureRuntime::GenerateMipmaps(const OGLTexture& tex, u32 max_level) { void TextureRuntime::GenerateMipmaps(OGLTexture& texture, u32 max_level) {
OpenGLState prev_state = OpenGLState::GetCurState(); OpenGLState prev_state = OpenGLState::GetCurState();
SCOPE_EXIT({ prev_state.Apply(); }); SCOPE_EXIT({ prev_state.Apply(); });
OpenGLState state; OpenGLState state{};
state.texture_units[0].texture_2d = tex.handle; state.texture_units[0].texture_2d = texture.handle;
state.Apply(); state.Apply();
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);

View File

@ -3,6 +3,7 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#pragma once #pragma once
#include <span>
#include "video_core/rasterizer_cache/types.h" #include "video_core/rasterizer_cache/types.h"
#include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/gl_resource_manager.h"
@ -19,26 +20,21 @@ public:
TextureRuntime(); TextureRuntime();
~TextureRuntime() = default; ~TextureRuntime() = default;
// Copies the GPU pixel data to the provided pixels buffer /// Copies the GPU pixel data to the provided pixels buffer
void ReadTexture(const OGLTexture& tex, Subresource subresource, const FormatTuple& tuple, void ReadTexture(OGLTexture& texture, const BufferTextureCopy& copy,
u8* pixels); PixelFormat format, std::span<std::byte> pixels);
// Fills the rectangle of the texture with the clear value provided /// Fills the rectangle of the texture with the clear value provided
bool ClearTexture(const OGLTexture& texture, Subresource subresource, ClearValue value); bool ClearTexture(OGLTexture& texture, const ClearRect& rect, ClearValue value);
// Copies a rectangle of src_tex to another rectange of dst_rect /// Copies a rectangle of src_tex to another rectange of dst_rect
// NOTE: The width and height of the rectangles must be equal bool CopyTextures(OGLTexture& source, OGLTexture& dest, const TextureCopy& copy);
bool CopyTextures(const OGLTexture& src_tex, Subresource src_subresource,
const OGLTexture& dst_tex, Subresource dst_subresource);
// Copies a rectangle of src_tex to another rectange of dst_rect performing /// Blits a rectangle of src_tex to another rectange of dst_rect
// scaling and format conversions bool BlitTextures(OGLTexture& source, OGLTexture& dest, const TextureBlit& blit);
bool BlitTextures(const OGLTexture& src_tex, Subresource src_subresource,
const OGLTexture& dst_tex, Subresource dst_subresource,
bool dst_cube = false);
// Generates mipmaps for all the available levels of the texture /// Generates mipmaps for all the available levels of the texture
void GenerateMipmaps(const OGLTexture& tex, u32 max_level); void GenerateMipmaps(OGLTexture& texture, u32 max_level);
private: private:
OGLFramebuffer read_fbo, draw_fbo; OGLFramebuffer read_fbo, draw_fbo;

View File

@ -3,13 +3,40 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#pragma once #pragma once
#include "common/math_util.h" #include "common/common_types.h"
#include "common/vector_math.h" #include "common/vector_math.h"
#include "video_core/rasterizer_cache/pixel_format.h" #include "video_core/rasterizer_cache/pixel_format.h"
namespace OpenGL { namespace OpenGL {
// A union for both color and depth/stencil clear values struct Offset {
constexpr auto operator<=>(const Offset&) const noexcept = default;
u32 x = 0;
u32 y = 0;
};
struct Extent {
constexpr auto operator<=>(const Extent&) const noexcept = default;
u32 width = 1;
u32 height = 1;
};
struct Rect2D {
constexpr auto operator<=>(const Rect2D&) const noexcept = default;
Offset offset;
Extent extent;
};
struct Region2D {
constexpr auto operator<=>(const Region2D&) const noexcept = default;
Offset start;
Offset end;
};
union ClearValue { union ClearValue {
Common::Vec4f color; Common::Vec4f color;
struct { struct {
@ -18,13 +45,44 @@ union ClearValue {
}; };
}; };
struct Subresource { struct ClearRect {
auto operator<=>(const Subresource&) const = default; SurfaceType surface_type;
u32 texture_level;
Rect2D rect;
};
SurfaceType type; struct TextureCopy {
Common::Rectangle<u32> region; SurfaceType surface_type;
u32 level = 0; u32 src_level;
u32 layer = 0; u32 dst_level;
Offset src_offset;
Offset dst_offset;
Extent extent;
};
struct TextureBlit {
SurfaceType surface_type;
u32 src_level;
u32 dst_level;
Region2D src_region;
Region2D dst_region;
};
struct BufferTextureCopy {
u32 buffer_offset;
u32 buffer_size;
u32 buffer_row_length;
u32 buffer_height;
SurfaceType surface_type;
u32 texture_level;
Offset texture_offset;
Extent texture_extent;
};
struct BufferCopy {
u32 src_offset;
u32 dst_offset;
u32 size;
}; };
} // namespace OpenGL } // namespace OpenGL