rasterizer_cache: Improve TextureRuntime API
* This makes every operation more explicit and mimics more the Vulkan API
This commit is contained in:
@ -337,17 +337,21 @@ void CachedSurface::UploadGLTexture(Common::Rectangle<u32> rect) {
|
||||
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)) {
|
||||
const Subresource src_subresource = {
|
||||
.type = type,
|
||||
.region = from_rect
|
||||
const TextureBlit texture_blit = {
|
||||
.surface_type = type,
|
||||
.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 = {
|
||||
.type = type,
|
||||
.region = scaled_rect
|
||||
};
|
||||
|
||||
runtime.BlitTextures(unscaled_tex, src_subresource, texture, dst_subresource);
|
||||
runtime.BlitTextures(unscaled_tex, texture, texture_blit);
|
||||
}
|
||||
}
|
||||
|
||||
@ -363,8 +367,10 @@ void CachedSurface::DownloadGLTexture(const Common::Rectangle<u32>& rect) {
|
||||
|
||||
MICROPROFILE_SCOPE(RasterizerCache_TextureDL);
|
||||
|
||||
const u32 download_size = width * height * GetBytesPerPixel(pixel_format);
|
||||
|
||||
if (gl_buffer.empty()) {
|
||||
gl_buffer.resize(width * height * GetBytesPerPixel(pixel_format));
|
||||
gl_buffer.resize(download_size);
|
||||
}
|
||||
|
||||
OpenGLState state = OpenGLState::GetCurState();
|
||||
@ -374,10 +380,7 @@ void CachedSurface::DownloadGLTexture(const Common::Rectangle<u32>& rect) {
|
||||
// Ensure no bad interactions with GL_PACK_ALIGNMENT
|
||||
ASSERT(stride * GetBytesPerPixel(pixel_format) % 4 == 0);
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(stride));
|
||||
const std::size_t buffer_offset =
|
||||
(rect.bottom * stride + rect.left) * GetBytesPerPixel(pixel_format);
|
||||
|
||||
const FormatTuple& tuple = GetFormatTuple(pixel_format);
|
||||
const u32 buffer_offset = (rect.bottom * stride + rect.left) * GetBytesPerPixel(pixel_format);
|
||||
|
||||
// If not 1x scale, blit scaled texture to a new 1x texture and use that to flush
|
||||
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};
|
||||
auto unscaled_tex = owner.AllocateSurfaceTexture(pixel_format, rect.GetWidth(), rect.GetHeight());
|
||||
|
||||
const Subresource src_subresource = {
|
||||
.type = type,
|
||||
.region = scaled_rect
|
||||
};
|
||||
|
||||
const Subresource dst_subresource = {
|
||||
.type = type,
|
||||
.region = unscaled_tex_rect
|
||||
const TextureBlit texture_blit = {
|
||||
.surface_type = type,
|
||||
.src_level = 0,
|
||||
.dst_level = 0,
|
||||
.src_region = Region2D{
|
||||
.start = {scaled_rect.left, scaled_rect.bottom},
|
||||
.end = {scaled_rect.right, scaled_rect.top}
|
||||
},
|
||||
.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
|
||||
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.Apply();
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
const FormatTuple& tuple = GetFormatTuple(pixel_format);
|
||||
if (GLES) {
|
||||
owner.texture_downloader_es->GetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type,
|
||||
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]);
|
||||
}
|
||||
} else {
|
||||
const Subresource subresource = {
|
||||
.type = type,
|
||||
.region = rect
|
||||
const BufferTextureCopy texture_download = {
|
||||
.buffer_offset = buffer_offset,
|
||||
.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);
|
||||
|
@ -49,11 +49,7 @@ void RasterizerCache::CopySurface(const Surface& src_surface, const Surface& dst
|
||||
SurfaceParams subrect_params = dst_surface->FromInterval(copy_interval);
|
||||
ASSERT(subrect_params.GetInterval() == copy_interval && src_surface != dst_surface);
|
||||
|
||||
const Subresource dst_subresource = {
|
||||
.type = dst_surface->type,
|
||||
.region = dst_surface->GetScaledSubRect(subrect_params)
|
||||
};
|
||||
|
||||
const auto dst_rect = dst_surface->GetScaledSubRect(subrect_params);
|
||||
if (src_surface->type == SurfaceType::Fill) {
|
||||
// FillSurface needs a 4 bytes buffer
|
||||
const u32 fill_offset =
|
||||
@ -68,18 +64,36 @@ void RasterizerCache::CopySurface(const Surface& src_surface, const Surface& dst
|
||||
const ClearValue clear_value =
|
||||
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;
|
||||
}
|
||||
|
||||
if (src_surface->CanSubRect(subrect_params)) {
|
||||
const Subresource src_subresource = {
|
||||
.type = src_surface->type,
|
||||
.region = src_surface->GetScaledSubRect(subrect_params)
|
||||
const auto src_rect = src_surface->GetScaledSubRect(subrect_params);
|
||||
const TextureBlit texture_blit = {
|
||||
.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,
|
||||
dst_subresource);
|
||||
runtime.BlitTextures(src_surface->texture, dst_surface->texture, texture_blit);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -210,18 +224,21 @@ bool RasterizerCache::BlitSurfaces(const Surface& src_surface,
|
||||
if (CheckFormatsBlittable(src_surface->pixel_format, dst_surface->pixel_format)) {
|
||||
dst_surface->InvalidateAllWatcher();
|
||||
|
||||
const Subresource src_subresource = {
|
||||
.type = src_surface->type,
|
||||
.region = src_rect
|
||||
const TextureBlit texture_blit = {
|
||||
.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}
|
||||
}
|
||||
};
|
||||
|
||||
const Subresource dst_subresource = {
|
||||
.type = dst_surface->type,
|
||||
.region = dst_rect
|
||||
};
|
||||
|
||||
return runtime.BlitTextures(src_surface->texture, src_subresource,
|
||||
dst_surface->texture, dst_subresource);
|
||||
return runtime.BlitTextures(src_surface->texture, dst_surface->texture, texture_blit);
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -441,19 +458,23 @@ Surface RasterizerCache::GetTextureSurface(const Pica::Texture::TextureInfo& inf
|
||||
}
|
||||
|
||||
if (!surface->is_custom && texture_filterer->IsNull()) {
|
||||
const Subresource src_subresource = {
|
||||
.type = surface->type,
|
||||
.region = level_surface->GetScaledRect()
|
||||
const auto src_rect = level_surface->GetScaledRect();
|
||||
const auto dst_rect = surface_params.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 = {
|
||||
.type = surface->type,
|
||||
.region = surface_params.GetScaledRect(),
|
||||
.level = level
|
||||
};
|
||||
|
||||
runtime.BlitTextures(level_surface->texture, src_subresource,
|
||||
surface->texture, dst_subresource);
|
||||
runtime.BlitTextures(level_surface->texture, surface->texture, texture_blit);
|
||||
}
|
||||
|
||||
watcher->Validate();
|
||||
@ -530,19 +551,22 @@ const CachedTextureCube& RasterizerCache::GetTextureCube(const TextureCubeConfig
|
||||
ValidateSurface(surface, surface->addr, surface->size);
|
||||
}
|
||||
|
||||
const Subresource src_subresource = {
|
||||
.type = surface->type,
|
||||
.region = surface->GetScaledRect()
|
||||
const auto src_rect = surface->GetScaledRect();
|
||||
const TextureBlit texture_blit = {
|
||||
.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 = {
|
||||
.type = surface->type,
|
||||
.region = Common::Rectangle<u32>{0, scaled_size, scaled_size, 0}
|
||||
};
|
||||
|
||||
runtime.BlitTextures(surface->texture, src_subresource,
|
||||
cube.texture, dst_subresource);
|
||||
|
||||
runtime.BlitTextures(surface->texture, cube.texture, texture_blit);
|
||||
face.watcher->Validate();
|
||||
}
|
||||
}
|
||||
@ -857,22 +881,24 @@ bool RasterizerCache::ValidateByReinterpretation(const Surface& surface,
|
||||
reinterpreter->Reinterpret(reinterpret_surface->texture, src_rect, tmp_tex,
|
||||
tmp_rect);
|
||||
|
||||
if (!texture_filterer->Filter(tmp_tex, tmp_rect, surface->texture, dest_rect,
|
||||
type)) {
|
||||
|
||||
const Subresource src_subresource = {
|
||||
.type = type,
|
||||
.region = tmp_rect
|
||||
if (!texture_filterer->Filter(tmp_tex, tmp_rect, surface->texture, dest_rect, type)) {
|
||||
const TextureBlit texture_blit = {
|
||||
.surface_type = type,
|
||||
.src_level = 0,
|
||||
.dst_level = 0,
|
||||
.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 = {
|
||||
.type = type,
|
||||
.region = dest_rect
|
||||
};
|
||||
|
||||
runtime.BlitTextures(tmp_tex, src_subresource,
|
||||
surface->texture, dst_subresource);
|
||||
runtime.BlitTextures(tmp_tex, surface->texture, texture_blit);
|
||||
}
|
||||
|
||||
} else {
|
||||
reinterpreter->Reinterpret(reinterpret_surface->texture, src_rect, surface->texture,
|
||||
dest_rect);
|
||||
|
@ -31,70 +31,69 @@ TextureRuntime::TextureRuntime() {
|
||||
draw_fbo.Create();
|
||||
}
|
||||
|
||||
void TextureRuntime::ReadTexture(const OGLTexture& tex, Subresource subresource,
|
||||
const FormatTuple& tuple, u8* pixels) {
|
||||
void TextureRuntime::ReadTexture(OGLTexture& texture, const BufferTextureCopy& copy,
|
||||
PixelFormat format, std::span<std::byte> pixels) {
|
||||
|
||||
OpenGLState prev_state = OpenGLState::GetCurState();
|
||||
SCOPE_EXIT({ prev_state.Apply(); });
|
||||
|
||||
OpenGLState state;
|
||||
state.ResetTexture(tex.handle);
|
||||
OpenGLState state{};
|
||||
state.ResetTexture(texture.handle);
|
||||
state.draw.read_framebuffer = read_fbo.handle;
|
||||
state.Apply();
|
||||
|
||||
const u32 level = subresource.level;
|
||||
switch (subresource.type) {
|
||||
switch (copy.surface_type) {
|
||||
case SurfaceType::Color:
|
||||
case SurfaceType::Texture:
|
||||
case SurfaceType::Fill:
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex.handle,
|
||||
level);
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.handle,
|
||||
copy.texture_level);
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
|
||||
0);
|
||||
break;
|
||||
case SurfaceType::Depth:
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, tex.handle,
|
||||
level);
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texture.handle,
|
||||
copy.texture_level);
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
|
||||
break;
|
||||
case SurfaceType::DepthStencil:
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
|
||||
tex.handle, level);
|
||||
texture.handle, copy.texture_level);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE_MSG("Invalid surface type!");
|
||||
}
|
||||
|
||||
const auto& rect = subresource.region;
|
||||
glReadPixels(rect.left, rect.bottom, rect.GetWidth(), rect.GetHeight(), tuple.format,
|
||||
tuple.type, pixels);
|
||||
// TODO: Use PBO here
|
||||
const FormatTuple& tuple = GetFormatTuple(format);
|
||||
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,
|
||||
ClearValue value) {
|
||||
bool TextureRuntime::ClearTexture(OGLTexture& texture, const ClearRect& rect, ClearValue value) {
|
||||
OpenGLState prev_state = OpenGLState::GetCurState();
|
||||
SCOPE_EXIT({ prev_state.Apply(); });
|
||||
|
||||
// Setup scissor rectangle according to the clear rectangle
|
||||
const auto& clear_rect = subresource.region;
|
||||
OpenGLState state;
|
||||
OpenGLState state{};
|
||||
state.scissor.enabled = true;
|
||||
state.scissor.x = clear_rect.left;
|
||||
state.scissor.y = clear_rect.bottom;
|
||||
state.scissor.width = clear_rect.GetWidth();
|
||||
state.scissor.height = clear_rect.GetHeight();
|
||||
state.scissor.x = rect.rect.offset.x;
|
||||
state.scissor.y = rect.rect.offset.y;
|
||||
state.scissor.width = rect.rect.extent.width;
|
||||
state.scissor.height = rect.rect.extent.height;
|
||||
state.draw.draw_framebuffer = draw_fbo.handle;
|
||||
state.Apply();
|
||||
|
||||
const u32 level = subresource.level;
|
||||
switch (subresource.type) {
|
||||
switch (rect.surface_type) {
|
||||
case SurfaceType::Color:
|
||||
case SurfaceType::Texture:
|
||||
case SurfaceType::Fill:
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex.handle,
|
||||
level);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.handle,
|
||||
rect.texture_level);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
|
||||
0);
|
||||
|
||||
@ -108,8 +107,8 @@ bool TextureRuntime::ClearTexture(const OGLTexture& tex, Subresource subresource
|
||||
break;
|
||||
case SurfaceType::Depth:
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, tex.handle,
|
||||
level);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texture.handle,
|
||||
rect.texture_level);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
|
||||
|
||||
state.depth.write_mask = GL_TRUE;
|
||||
@ -120,7 +119,7 @@ bool TextureRuntime::ClearTexture(const OGLTexture& tex, Subresource subresource
|
||||
case SurfaceType::DepthStencil:
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
||||
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.stencil.write_mask = -1;
|
||||
@ -135,50 +134,42 @@ bool TextureRuntime::ClearTexture(const OGLTexture& tex, Subresource subresource
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextureRuntime::CopyTextures(const OGLTexture& src_tex, Subresource src_subresource,
|
||||
const OGLTexture& dst_tex, Subresource dst_subresource) {
|
||||
bool TextureRuntime::CopyTextures(OGLTexture& source, OGLTexture& dest, const TextureCopy& copy) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextureRuntime::BlitTextures(const OGLTexture& src_tex, Subresource src_subresource,
|
||||
const OGLTexture& dst_tex, Subresource dst_subresource,
|
||||
bool dst_cube) {
|
||||
bool TextureRuntime::BlitTextures(OGLTexture& source, OGLTexture& dest, const TextureBlit& blit) {
|
||||
OpenGLState prev_state = OpenGLState::GetCurState();
|
||||
SCOPE_EXIT({ prev_state.Apply(); });
|
||||
|
||||
OpenGLState state;
|
||||
OpenGLState state{};
|
||||
state.draw.read_framebuffer = read_fbo.handle;
|
||||
state.draw.draw_framebuffer = draw_fbo.handle;
|
||||
state.Apply();
|
||||
|
||||
auto BindAttachment =
|
||||
[dst_cube, src_level = src_subresource.level, dst_level = dst_subresource.level,
|
||||
dst_layer = dst_subresource.layer](GLenum target, u32 src_tex, u32 dst_tex) -> void {
|
||||
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);
|
||||
auto BindAttachment = [&blit](GLenum target, u32 src_tex, u32 dst_tex) -> void {
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, target, GL_TEXTURE_2D, src_tex, blit.src_level);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, target, GL_TEXTURE_2D, dst_tex, blit.dst_level);
|
||||
};
|
||||
|
||||
// Sanity check; Can't blit a color texture to a depth buffer
|
||||
ASSERT(src_subresource.type == dst_subresource.type);
|
||||
switch (src_subresource.type) {
|
||||
switch (blit.surface_type) {
|
||||
case SurfaceType::Color:
|
||||
case SurfaceType::Texture:
|
||||
case SurfaceType::Fill:
|
||||
// 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);
|
||||
break;
|
||||
case SurfaceType::Depth:
|
||||
// Bind only depth
|
||||
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);
|
||||
break;
|
||||
case SurfaceType::DepthStencil:
|
||||
// Bind to combined depth + stencil
|
||||
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;
|
||||
default:
|
||||
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
|
||||
// well-programmed game this code path should be rarely executed for shadow map with
|
||||
// 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 auto& src_rect = src_subresource.region;
|
||||
const auto& dst_rect = dst_subresource.region;
|
||||
glBlitFramebuffer(src_rect.left, src_rect.bottom, src_rect.right, src_rect.top, dst_rect.left,
|
||||
dst_rect.bottom, dst_rect.right, dst_rect.top,
|
||||
glBlitFramebuffer(blit.src_region.start.x, blit.src_region.start.y,
|
||||
blit.src_region.end.x, blit.src_region.end.y,
|
||||
blit.dst_region.start.x, blit.dst_region.start.y,
|
||||
blit.dst_region.end.x, blit.dst_region.end.y,
|
||||
buffer_mask, filter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TextureRuntime::GenerateMipmaps(const OGLTexture& tex, u32 max_level) {
|
||||
void TextureRuntime::GenerateMipmaps(OGLTexture& texture, u32 max_level) {
|
||||
OpenGLState prev_state = OpenGLState::GetCurState();
|
||||
SCOPE_EXIT({ prev_state.Apply(); });
|
||||
|
||||
OpenGLState state;
|
||||
state.texture_units[0].texture_2d = tex.handle;
|
||||
OpenGLState state{};
|
||||
state.texture_units[0].texture_2d = texture.handle;
|
||||
state.Apply();
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
@ -3,6 +3,7 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
#include <span>
|
||||
#include "video_core/rasterizer_cache/types.h"
|
||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||
|
||||
@ -19,26 +20,21 @@ public:
|
||||
TextureRuntime();
|
||||
~TextureRuntime() = default;
|
||||
|
||||
// Copies the GPU pixel data to the provided pixels buffer
|
||||
void ReadTexture(const OGLTexture& tex, Subresource subresource, const FormatTuple& tuple,
|
||||
u8* pixels);
|
||||
/// Copies the GPU pixel data to the provided pixels buffer
|
||||
void ReadTexture(OGLTexture& texture, const BufferTextureCopy& copy,
|
||||
PixelFormat format, std::span<std::byte> pixels);
|
||||
|
||||
// Fills the rectangle of the texture with the clear value provided
|
||||
bool ClearTexture(const OGLTexture& texture, Subresource subresource, ClearValue value);
|
||||
/// Fills the rectangle of the texture with the clear value provided
|
||||
bool ClearTexture(OGLTexture& texture, const ClearRect& rect, ClearValue value);
|
||||
|
||||
// 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(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
|
||||
bool CopyTextures(OGLTexture& source, OGLTexture& dest, const TextureCopy& copy);
|
||||
|
||||
// Copies a rectangle of src_tex to another rectange of dst_rect performing
|
||||
// scaling and format conversions
|
||||
bool BlitTextures(const OGLTexture& src_tex, Subresource src_subresource,
|
||||
const OGLTexture& dst_tex, Subresource dst_subresource,
|
||||
bool dst_cube = false);
|
||||
/// Blits a rectangle of src_tex to another rectange of dst_rect
|
||||
bool BlitTextures(OGLTexture& source, OGLTexture& dest, const TextureBlit& blit);
|
||||
|
||||
// Generates mipmaps for all the available levels of the texture
|
||||
void GenerateMipmaps(const OGLTexture& tex, u32 max_level);
|
||||
/// Generates mipmaps for all the available levels of the texture
|
||||
void GenerateMipmaps(OGLTexture& texture, u32 max_level);
|
||||
|
||||
private:
|
||||
OGLFramebuffer read_fbo, draw_fbo;
|
||||
|
@ -3,13 +3,40 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
#include "common/math_util.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/vector_math.h"
|
||||
#include "video_core/rasterizer_cache/pixel_format.h"
|
||||
|
||||
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 {
|
||||
Common::Vec4f color;
|
||||
struct {
|
||||
@ -18,13 +45,44 @@ union ClearValue {
|
||||
};
|
||||
};
|
||||
|
||||
struct Subresource {
|
||||
auto operator<=>(const Subresource&) const = default;
|
||||
struct ClearRect {
|
||||
SurfaceType surface_type;
|
||||
u32 texture_level;
|
||||
Rect2D rect;
|
||||
};
|
||||
|
||||
SurfaceType type;
|
||||
Common::Rectangle<u32> region;
|
||||
u32 level = 0;
|
||||
u32 layer = 0;
|
||||
struct TextureCopy {
|
||||
SurfaceType surface_type;
|
||||
u32 src_level;
|
||||
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
|
||||
|
Reference in New Issue
Block a user