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};
|
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);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
Reference in New Issue
Block a user