mirror of
https://github.com/Lime3DS/Lime3DS.git
synced 2026-07-09 17:24:49 -06:00
renderer_gl: Fix OpenGL texture unit state tracking (#2242)
* video_core: Implement texture-layer clears Allow specific texture-layers to be targetted for clears rather than just defaulting to the first layer, or clearing all layers after in the case of Vulkan. Allows specific faces of a cubemap to be cleared. * video_core: Initialize `NULL_SURFACE_CUBE_ID` Properly initialize the `NULL_SURFACE_CUBE_ID` texture to ensure that all 6 of its faces are black-transparent. * renderer_gl: Add explicit texture-unit target state tracking The `.target` field can be either a `GL_TEXTURE_2D` or a `GL_TEXTURE_CUBE_MAP` and must be explicitly set when assigning the `.texture_2d` or there is a risk of leaking a previous texture state into the current one in the case that a texture-cube was binded into slot 0 and it becomes a texture-2d sometime after.
This commit is contained in:
parent
7c225c6abb
commit
d93adebb16
@ -71,12 +71,28 @@ RasterizerCache<T>::RasterizerCache(Memory::MemorySystem& memory_,
|
||||
auto& null_surface = slot_surfaces[NULL_SURFACE_ID];
|
||||
runtime.ClearTexture(null_surface, {
|
||||
.texture_level = 0,
|
||||
.texture_layer = 0,
|
||||
.texture_rect = null_surface.GetScaledRect(),
|
||||
.value =
|
||||
{
|
||||
.color = {0.f, 0.f, 0.f, 0.f},
|
||||
},
|
||||
});
|
||||
|
||||
auto& null_surface_cube = slot_surfaces[NULL_SURFACE_CUBE_ID];
|
||||
// Clear all cubemap faces
|
||||
for (u32 cube_layer_index = 0; cube_layer_index < 6; ++cube_layer_index) {
|
||||
runtime.ClearTexture(null_surface_cube,
|
||||
{
|
||||
.texture_level = 0,
|
||||
.texture_layer = cube_layer_index,
|
||||
.texture_rect = null_surface_cube.GetScaledRect(),
|
||||
.value =
|
||||
{
|
||||
.color = {0.f, 0.f, 0.f, 0.f},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -30,6 +30,7 @@ union ClearValue {
|
||||
|
||||
struct TextureClear {
|
||||
u32 texture_level;
|
||||
u32 texture_layer;
|
||||
Common::Rectangle<u32> texture_rect;
|
||||
ClearValue value;
|
||||
};
|
||||
|
||||
@ -88,6 +88,7 @@ bool BlitHelper::ConvertDS24S8ToRGBA8(Surface& source, Surface& dest,
|
||||
SCOPE_EXIT({ prev_state.Apply(); });
|
||||
|
||||
state.texture_units[0].texture_2d = source.Handle();
|
||||
state.texture_units[0].target = GL_TEXTURE_2D;
|
||||
state.texture_units[0].sampler = 0;
|
||||
state.texture_units[1].sampler = 0;
|
||||
|
||||
@ -103,6 +104,7 @@ bool BlitHelper::ConvertDS24S8ToRGBA8(Surface& source, Surface& dest,
|
||||
temp_tex.Release();
|
||||
temp_tex.Create();
|
||||
state.texture_units[1].texture_2d = temp_tex.handle;
|
||||
state.texture_units[1].target = GL_TEXTURE_2D;
|
||||
state.Apply();
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH24_STENCIL8, temp_extent.width,
|
||||
@ -111,6 +113,7 @@ bool BlitHelper::ConvertDS24S8ToRGBA8(Surface& source, Surface& dest,
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
}
|
||||
state.texture_units[1].texture_2d = temp_tex.handle;
|
||||
state.texture_units[1].target = GL_TEXTURE_2D;
|
||||
state.Apply();
|
||||
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
@ -145,6 +148,7 @@ bool BlitHelper::ConvertRGBA4ToRGB5A1(Surface& source, Surface& dest,
|
||||
SCOPE_EXIT({ prev_state.Apply(); });
|
||||
|
||||
state.texture_units[0].texture_2d = source.Handle();
|
||||
state.texture_units[0].target = GL_TEXTURE_2D;
|
||||
|
||||
const Common::Rectangle src_rect{copy.src_offset.x, copy.src_offset.y + copy.extent.height,
|
||||
copy.src_offset.x + copy.extent.width, copy.src_offset.x};
|
||||
@ -206,6 +210,7 @@ void BlitHelper::FilterAnime4K(Surface& surface, const VideoCore::TextureBlit& b
|
||||
texture.fbo.Create();
|
||||
texture.tex.Create();
|
||||
state.texture_units[1].texture_2d = texture.tex.handle;
|
||||
state.texture_units[1].target = GL_TEXTURE_2D;
|
||||
state.draw.draw_framebuffer = texture.fbo.handle;
|
||||
state.Apply();
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
@ -228,6 +233,10 @@ void BlitHelper::FilterAnime4K(Surface& surface, const VideoCore::TextureBlit& b
|
||||
state.texture_units[1].texture_2d = LUMAD.tex.handle;
|
||||
state.texture_units[2].texture_2d = XY.tex.handle;
|
||||
|
||||
state.texture_units[0].target = GL_TEXTURE_2D;
|
||||
state.texture_units[1].target = GL_TEXTURE_2D;
|
||||
state.texture_units[2].target = GL_TEXTURE_2D;
|
||||
|
||||
// gradient x pass
|
||||
Draw(gradient_x_program, XY.tex.handle, XY.fbo.handle, 0, temp_rect);
|
||||
|
||||
@ -249,6 +258,7 @@ void BlitHelper::FilterBicubic(Surface& surface, const VideoCore::TextureBlit& b
|
||||
const OpenGLState prev_state = OpenGLState::GetCurState();
|
||||
SCOPE_EXIT({ prev_state.Apply(); });
|
||||
state.texture_units[0].texture_2d = surface.Handle(0);
|
||||
state.texture_units[0].target = GL_TEXTURE_2D;
|
||||
SetParams(bicubic_program, surface.RealExtent(false), blit.src_rect);
|
||||
Draw(bicubic_program, surface.Handle(), draw_fbo.handle, blit.dst_level, blit.dst_rect);
|
||||
}
|
||||
@ -257,6 +267,7 @@ void BlitHelper::FilterScaleForce(Surface& surface, const VideoCore::TextureBlit
|
||||
const OpenGLState prev_state = OpenGLState::GetCurState();
|
||||
SCOPE_EXIT({ prev_state.Apply(); });
|
||||
state.texture_units[0].texture_2d = surface.Handle(0);
|
||||
state.texture_units[0].target = GL_TEXTURE_2D;
|
||||
SetParams(scale_force_program, surface.RealExtent(false), blit.src_rect);
|
||||
Draw(scale_force_program, surface.Handle(), draw_fbo.handle, blit.dst_level, blit.dst_rect);
|
||||
}
|
||||
@ -265,6 +276,7 @@ void BlitHelper::FilterXbrz(Surface& surface, const VideoCore::TextureBlit& blit
|
||||
const OpenGLState prev_state = OpenGLState::GetCurState();
|
||||
SCOPE_EXIT({ prev_state.Apply(); });
|
||||
state.texture_units[0].texture_2d = surface.Handle(0);
|
||||
state.texture_units[0].target = GL_TEXTURE_2D;
|
||||
glProgramUniform1f(xbrz_program.handle, 2, static_cast<GLfloat>(surface.res_scale));
|
||||
SetParams(xbrz_program, surface.RealExtent(false), blit.src_rect);
|
||||
Draw(xbrz_program, surface.Handle(), draw_fbo.handle, blit.dst_level, blit.dst_rect);
|
||||
@ -274,6 +286,7 @@ void BlitHelper::FilterMMPX(Surface& surface, const VideoCore::TextureBlit& blit
|
||||
const OpenGLState prev_state = OpenGLState::GetCurState();
|
||||
SCOPE_EXIT({ prev_state.Apply(); });
|
||||
state.texture_units[0].texture_2d = surface.Handle(0);
|
||||
state.texture_units[0].target = GL_TEXTURE_2D;
|
||||
SetParams(mmpx_program, surface.RealExtent(false), blit.src_rect);
|
||||
Draw(mmpx_program, surface.Handle(), draw_fbo.handle, blit.dst_level, blit.dst_rect);
|
||||
}
|
||||
|
||||
@ -717,6 +717,7 @@ void RasterizerOpenGL::SyncTextureUnits(const Framebuffer* framebuffer) {
|
||||
if (!IsFeedbackLoop(texture_index, framebuffer, surface)) {
|
||||
BindMaterial(texture_index, surface);
|
||||
state.texture_units[texture_index].texture_2d = surface.Handle();
|
||||
state.texture_units[texture_index].target = GL_TEXTURE_2D;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -222,8 +222,9 @@ bool TextureRuntime::ClearTextureWithoutFbo(Surface& surface,
|
||||
UNREACHABLE_MSG("Unknown surface type {}", surface.type);
|
||||
}
|
||||
glClearTexSubImage(surface.Handle(), clear.texture_level, clear.texture_rect.left,
|
||||
clear.texture_rect.bottom, 0, clear.texture_rect.GetWidth(),
|
||||
clear.texture_rect.GetHeight(), 1, format, type, &clear.value);
|
||||
clear.texture_rect.bottom, clear.texture_layer,
|
||||
clear.texture_rect.GetWidth(), clear.texture_rect.GetHeight(), 1, format,
|
||||
type, &clear.value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -245,7 +246,7 @@ void TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
|
||||
state.draw.draw_framebuffer = draw_fbos[FboIndex(surface.type)].handle;
|
||||
state.Apply();
|
||||
|
||||
surface.Attach(GL_DRAW_FRAMEBUFFER, clear.texture_level, 0);
|
||||
surface.Attach(GL_DRAW_FRAMEBUFFER, clear.texture_level, clear.texture_layer);
|
||||
|
||||
switch (surface.type) {
|
||||
case SurfaceType::Color:
|
||||
@ -326,6 +327,7 @@ void TextureRuntime::GenerateMipmaps(Surface& surface) {
|
||||
|
||||
const auto generate = [&](u32 index) {
|
||||
state.texture_units[0].texture_2d = surface.Handle(index);
|
||||
state.texture_units[0].target = GL_TEXTURE_2D;
|
||||
state.Apply();
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, surface.levels - 1);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
@ -554,6 +556,7 @@ bool Surface::DownloadWithoutFbo(const VideoCore::BufferTextureCopy& download,
|
||||
// that only support up to 4.3
|
||||
OpenGLState state = OpenGLState::GetCurState();
|
||||
state.texture_units[0].texture_2d = Handle(0);
|
||||
state.texture_units[0].target = GL_TEXTURE_2D;
|
||||
state.Apply();
|
||||
|
||||
glGetTexImage(GL_TEXTURE_2D, download.texture_level, tuple.format, tuple.type,
|
||||
|
||||
@ -350,8 +350,8 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
|
||||
.aspectMask = params.aspect,
|
||||
.baseMipLevel = clear.texture_level,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
.baseArrayLayer = clear.texture_layer,
|
||||
.layerCount = 1,
|
||||
};
|
||||
|
||||
const vk::ImageMemoryBarrier pre_barrier = {
|
||||
@ -436,7 +436,8 @@ void TextureRuntime::ClearTextureWithRenderpass(Surface& surface,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = params.src_image,
|
||||
.subresourceRange = MakeSubresourceRange(params.aspect, clear.texture_level),
|
||||
.subresourceRange =
|
||||
MakeSubresourceRange(params.aspect, clear.texture_level, 1, clear.texture_layer),
|
||||
};
|
||||
|
||||
const vk::ImageMemoryBarrier post_barrier = {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user