Merge pull request #2071 from ReinUsesLisp/dsa-texture
gl_rasterizer: Use DSA for textures and move swizzling to texture state
This commit is contained in:
commit
40ac058557
|
@ -1019,11 +1019,8 @@ void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& s
|
||||||
if (surface != nullptr) {
|
if (surface != nullptr) {
|
||||||
unit.texture =
|
unit.texture =
|
||||||
entry.IsArray() ? surface->TextureLayer().handle : surface->Texture().handle;
|
entry.IsArray() ? surface->TextureLayer().handle : surface->Texture().handle;
|
||||||
unit.target = entry.IsArray() ? surface->TargetLayer() : surface->Target();
|
surface->UpdateSwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source,
|
||||||
unit.swizzle.r = MaxwellToGL::SwizzleSource(texture.tic.x_source);
|
texture.tic.w_source);
|
||||||
unit.swizzle.g = MaxwellToGL::SwizzleSource(texture.tic.y_source);
|
|
||||||
unit.swizzle.b = MaxwellToGL::SwizzleSource(texture.tic.z_source);
|
|
||||||
unit.swizzle.a = MaxwellToGL::SwizzleSource(texture.tic.w_source);
|
|
||||||
} else {
|
} else {
|
||||||
// Can occur when texture addr is null or its memory is unmapped/invalid
|
// Can occur when texture addr is null or its memory is unmapped/invalid
|
||||||
unit.texture = 0;
|
unit.texture = 0;
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
#include "video_core/morton.h"
|
#include "video_core/morton.h"
|
||||||
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
||||||
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
|
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
|
||||||
#include "video_core/renderer_opengl/gl_state.h"
|
|
||||||
#include "video_core/renderer_opengl/utils.h"
|
#include "video_core/renderer_opengl/utils.h"
|
||||||
#include "video_core/surface.h"
|
#include "video_core/surface.h"
|
||||||
#include "video_core/textures/astc.h"
|
#include "video_core/textures/astc.h"
|
||||||
|
@ -44,14 +43,14 @@ struct FormatTuple {
|
||||||
bool compressed;
|
bool compressed;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ApplyTextureDefaults(GLenum target, u32 max_mip_level) {
|
static void ApplyTextureDefaults(GLuint texture, u32 max_mip_level) {
|
||||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTextureParameteri(texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTextureParameteri(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTextureParameteri(texture, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glTextureParameteri(texture, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, max_mip_level - 1);
|
glTextureParameteri(texture, GL_TEXTURE_MAX_LEVEL, max_mip_level - 1);
|
||||||
if (max_mip_level == 1) {
|
if (max_mip_level == 1) {
|
||||||
glTexParameterf(target, GL_TEXTURE_LOD_BIAS, 1000.0);
|
glTextureParameterf(texture, GL_TEXTURE_LOD_BIAS, 1000.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,55 +528,41 @@ static void CopySurface(const Surface& src_surface, const Surface& dst_surface,
|
||||||
CachedSurface::CachedSurface(const SurfaceParams& params)
|
CachedSurface::CachedSurface(const SurfaceParams& params)
|
||||||
: params(params), gl_target(SurfaceTargetToGL(params.target)),
|
: params(params), gl_target(SurfaceTargetToGL(params.target)),
|
||||||
cached_size_in_bytes(params.size_in_bytes) {
|
cached_size_in_bytes(params.size_in_bytes) {
|
||||||
texture.Create();
|
texture.Create(gl_target);
|
||||||
const auto& rect{params.GetRect()};
|
|
||||||
|
|
||||||
// Keep track of previous texture bindings
|
// TODO(Rodrigo): Using params.GetRect() returns a different size than using its Mip*(0)
|
||||||
OpenGLState cur_state = OpenGLState::GetCurState();
|
// alternatives. This signals a bug on those functions.
|
||||||
const auto& old_tex = cur_state.texture_units[0];
|
const auto width = static_cast<GLsizei>(params.MipWidth(0));
|
||||||
SCOPE_EXIT({
|
const auto height = static_cast<GLsizei>(params.MipHeight(0));
|
||||||
cur_state.texture_units[0] = old_tex;
|
|
||||||
cur_state.Apply();
|
|
||||||
});
|
|
||||||
|
|
||||||
cur_state.texture_units[0].texture = texture.handle;
|
|
||||||
cur_state.texture_units[0].target = SurfaceTargetToGL(params.target);
|
|
||||||
cur_state.Apply();
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
|
|
||||||
const auto& format_tuple = GetFormatTuple(params.pixel_format, params.component_type);
|
const auto& format_tuple = GetFormatTuple(params.pixel_format, params.component_type);
|
||||||
gl_internal_format = format_tuple.internal_format;
|
gl_internal_format = format_tuple.internal_format;
|
||||||
gl_is_compressed = format_tuple.compressed;
|
|
||||||
|
|
||||||
if (!format_tuple.compressed) {
|
switch (params.target) {
|
||||||
// Only pre-create the texture for non-compressed textures.
|
case SurfaceTarget::Texture1D:
|
||||||
switch (params.target) {
|
glTextureStorage1D(texture.handle, params.max_mip_level, format_tuple.internal_format,
|
||||||
case SurfaceTarget::Texture1D:
|
width);
|
||||||
glTexStorage1D(SurfaceTargetToGL(params.target), params.max_mip_level,
|
break;
|
||||||
format_tuple.internal_format, rect.GetWidth());
|
case SurfaceTarget::Texture2D:
|
||||||
break;
|
case SurfaceTarget::TextureCubemap:
|
||||||
case SurfaceTarget::Texture2D:
|
glTextureStorage2D(texture.handle, params.max_mip_level, format_tuple.internal_format,
|
||||||
case SurfaceTarget::TextureCubemap:
|
width, height);
|
||||||
glTexStorage2D(SurfaceTargetToGL(params.target), params.max_mip_level,
|
break;
|
||||||
format_tuple.internal_format, rect.GetWidth(), rect.GetHeight());
|
case SurfaceTarget::Texture3D:
|
||||||
break;
|
case SurfaceTarget::Texture2DArray:
|
||||||
case SurfaceTarget::Texture3D:
|
case SurfaceTarget::TextureCubeArray:
|
||||||
case SurfaceTarget::Texture2DArray:
|
glTextureStorage3D(texture.handle, params.max_mip_level, format_tuple.internal_format,
|
||||||
case SurfaceTarget::TextureCubeArray:
|
width, height, params.depth);
|
||||||
glTexStorage3D(SurfaceTargetToGL(params.target), params.max_mip_level,
|
break;
|
||||||
format_tuple.internal_format, rect.GetWidth(), rect.GetHeight(),
|
default:
|
||||||
params.depth);
|
LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
|
||||||
break;
|
static_cast<u32>(params.target));
|
||||||
default:
|
UNREACHABLE();
|
||||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
|
glTextureStorage2D(texture.handle, params.max_mip_level, format_tuple.internal_format,
|
||||||
static_cast<u32>(params.target));
|
width, height);
|
||||||
UNREACHABLE();
|
|
||||||
glTexStorage2D(GL_TEXTURE_2D, params.max_mip_level, format_tuple.internal_format,
|
|
||||||
rect.GetWidth(), rect.GetHeight());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplyTextureDefaults(SurfaceTargetToGL(params.target), params.max_mip_level);
|
ApplyTextureDefaults(texture.handle, params.max_mip_level);
|
||||||
|
|
||||||
OpenGL::LabelGLObject(GL_TEXTURE, texture.handle, params.addr, params.IdentityString());
|
OpenGL::LabelGLObject(GL_TEXTURE, texture.handle, params.addr, params.IdentityString());
|
||||||
|
|
||||||
|
@ -751,63 +736,50 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
|
||||||
const auto& rect{params.GetRect(mip_map)};
|
const auto& rect{params.GetRect(mip_map)};
|
||||||
|
|
||||||
// Load data from memory to the surface
|
// Load data from memory to the surface
|
||||||
const GLint x0 = static_cast<GLint>(rect.left);
|
const auto x0 = static_cast<GLint>(rect.left);
|
||||||
const GLint y0 = static_cast<GLint>(rect.bottom);
|
const auto y0 = static_cast<GLint>(rect.bottom);
|
||||||
std::size_t buffer_offset =
|
auto buffer_offset =
|
||||||
static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.MipWidth(mip_map) +
|
static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.MipWidth(mip_map) +
|
||||||
static_cast<std::size_t>(x0)) *
|
static_cast<std::size_t>(x0)) *
|
||||||
GetBytesPerPixel(params.pixel_format);
|
GetBytesPerPixel(params.pixel_format);
|
||||||
|
|
||||||
const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
|
const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
|
||||||
const GLuint target_tex = texture.handle;
|
|
||||||
OpenGLState cur_state = OpenGLState::GetCurState();
|
|
||||||
|
|
||||||
const auto& old_tex = cur_state.texture_units[0];
|
|
||||||
SCOPE_EXIT({
|
|
||||||
cur_state.texture_units[0] = old_tex;
|
|
||||||
cur_state.Apply();
|
|
||||||
});
|
|
||||||
cur_state.texture_units[0].texture = target_tex;
|
|
||||||
cur_state.texture_units[0].target = SurfaceTargetToGL(params.target);
|
|
||||||
cur_state.Apply();
|
|
||||||
|
|
||||||
// Ensure no bad interactions with GL_UNPACK_ALIGNMENT
|
// Ensure no bad interactions with GL_UNPACK_ALIGNMENT
|
||||||
ASSERT(params.MipWidth(mip_map) * GetBytesPerPixel(params.pixel_format) % 4 == 0);
|
ASSERT(params.MipWidth(mip_map) * GetBytesPerPixel(params.pixel_format) % 4 == 0);
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.MipWidth(mip_map)));
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.MipWidth(mip_map)));
|
||||||
|
|
||||||
GLsizei image_size = static_cast<GLsizei>(params.GetMipmapSizeGL(mip_map, false));
|
const auto image_size = static_cast<GLsizei>(params.GetMipmapSizeGL(mip_map, false));
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
if (tuple.compressed) {
|
if (tuple.compressed) {
|
||||||
switch (params.target) {
|
switch (params.target) {
|
||||||
case SurfaceTarget::Texture2D:
|
case SurfaceTarget::Texture2D:
|
||||||
glCompressedTexImage2D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
|
glCompressedTextureSubImage2D(
|
||||||
static_cast<GLsizei>(params.MipWidth(mip_map)),
|
texture.handle, mip_map, 0, 0, static_cast<GLsizei>(params.MipWidth(mip_map)),
|
||||||
static_cast<GLsizei>(params.MipHeight(mip_map)), 0, image_size,
|
static_cast<GLsizei>(params.MipHeight(mip_map)), tuple.internal_format, image_size,
|
||||||
&gl_buffer[mip_map][buffer_offset]);
|
&gl_buffer[mip_map][buffer_offset]);
|
||||||
break;
|
break;
|
||||||
case SurfaceTarget::Texture3D:
|
case SurfaceTarget::Texture3D:
|
||||||
glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
|
glCompressedTextureSubImage3D(
|
||||||
static_cast<GLsizei>(params.MipWidth(mip_map)),
|
texture.handle, mip_map, 0, 0, 0, static_cast<GLsizei>(params.MipWidth(mip_map)),
|
||||||
static_cast<GLsizei>(params.MipHeight(mip_map)),
|
static_cast<GLsizei>(params.MipHeight(mip_map)),
|
||||||
static_cast<GLsizei>(params.MipDepth(mip_map)), 0, image_size,
|
static_cast<GLsizei>(params.MipDepth(mip_map)), tuple.internal_format, image_size,
|
||||||
&gl_buffer[mip_map][buffer_offset]);
|
&gl_buffer[mip_map][buffer_offset]);
|
||||||
break;
|
break;
|
||||||
case SurfaceTarget::Texture2DArray:
|
case SurfaceTarget::Texture2DArray:
|
||||||
case SurfaceTarget::TextureCubeArray:
|
case SurfaceTarget::TextureCubeArray:
|
||||||
glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
|
glCompressedTextureSubImage3D(
|
||||||
static_cast<GLsizei>(params.MipWidth(mip_map)),
|
texture.handle, mip_map, 0, 0, 0, static_cast<GLsizei>(params.MipWidth(mip_map)),
|
||||||
static_cast<GLsizei>(params.MipHeight(mip_map)),
|
static_cast<GLsizei>(params.MipHeight(mip_map)), static_cast<GLsizei>(params.depth),
|
||||||
static_cast<GLsizei>(params.depth), 0, image_size,
|
tuple.internal_format, image_size, &gl_buffer[mip_map][buffer_offset]);
|
||||||
&gl_buffer[mip_map][buffer_offset]);
|
|
||||||
break;
|
break;
|
||||||
case SurfaceTarget::TextureCubemap: {
|
case SurfaceTarget::TextureCubemap: {
|
||||||
GLsizei layer_size = static_cast<GLsizei>(params.LayerSizeGL(mip_map));
|
const auto layer_size = static_cast<GLsizei>(params.LayerSizeGL(mip_map));
|
||||||
for (std::size_t face = 0; face < params.depth; ++face) {
|
for (std::size_t face = 0; face < params.depth; ++face) {
|
||||||
glCompressedTexImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face),
|
glCompressedTextureSubImage3D(
|
||||||
mip_map, tuple.internal_format,
|
texture.handle, mip_map, 0, 0, static_cast<GLint>(face),
|
||||||
static_cast<GLsizei>(params.MipWidth(mip_map)),
|
static_cast<GLsizei>(params.MipWidth(mip_map)),
|
||||||
static_cast<GLsizei>(params.MipHeight(mip_map)), 0,
|
static_cast<GLsizei>(params.MipHeight(mip_map)), 1, tuple.internal_format,
|
||||||
layer_size, &gl_buffer[mip_map][buffer_offset]);
|
layer_size, &gl_buffer[mip_map][buffer_offset]);
|
||||||
buffer_offset += layer_size;
|
buffer_offset += layer_size;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -816,46 +788,43 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
|
||||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
|
LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
|
||||||
static_cast<u32>(params.target));
|
static_cast<u32>(params.target));
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
glCompressedTexImage2D(GL_TEXTURE_2D, mip_map, tuple.internal_format,
|
glCompressedTextureSubImage2D(
|
||||||
static_cast<GLsizei>(params.MipWidth(mip_map)),
|
texture.handle, mip_map, 0, 0, static_cast<GLsizei>(params.MipWidth(mip_map)),
|
||||||
static_cast<GLsizei>(params.MipHeight(mip_map)), 0,
|
static_cast<GLsizei>(params.MipHeight(mip_map)), tuple.internal_format,
|
||||||
static_cast<GLsizei>(params.size_in_bytes_gl),
|
static_cast<GLsizei>(params.size_in_bytes_gl), &gl_buffer[mip_map][buffer_offset]);
|
||||||
&gl_buffer[mip_map][buffer_offset]);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
switch (params.target) {
|
switch (params.target) {
|
||||||
case SurfaceTarget::Texture1D:
|
case SurfaceTarget::Texture1D:
|
||||||
glTexSubImage1D(SurfaceTargetToGL(params.target), mip_map, x0,
|
glTextureSubImage1D(texture.handle, mip_map, x0, static_cast<GLsizei>(rect.GetWidth()),
|
||||||
static_cast<GLsizei>(rect.GetWidth()), tuple.format, tuple.type,
|
tuple.format, tuple.type, &gl_buffer[mip_map][buffer_offset]);
|
||||||
&gl_buffer[mip_map][buffer_offset]);
|
|
||||||
break;
|
break;
|
||||||
case SurfaceTarget::Texture2D:
|
case SurfaceTarget::Texture2D:
|
||||||
glTexSubImage2D(SurfaceTargetToGL(params.target), mip_map, x0, y0,
|
glTextureSubImage2D(texture.handle, mip_map, x0, y0,
|
||||||
static_cast<GLsizei>(rect.GetWidth()),
|
static_cast<GLsizei>(rect.GetWidth()),
|
||||||
static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
|
static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
|
||||||
&gl_buffer[mip_map][buffer_offset]);
|
&gl_buffer[mip_map][buffer_offset]);
|
||||||
break;
|
break;
|
||||||
case SurfaceTarget::Texture3D:
|
case SurfaceTarget::Texture3D:
|
||||||
glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0,
|
glTextureSubImage3D(texture.handle, mip_map, x0, y0, 0,
|
||||||
static_cast<GLsizei>(rect.GetWidth()),
|
static_cast<GLsizei>(rect.GetWidth()),
|
||||||
static_cast<GLsizei>(rect.GetHeight()), params.MipDepth(mip_map),
|
static_cast<GLsizei>(rect.GetHeight()), params.MipDepth(mip_map),
|
||||||
tuple.format, tuple.type, &gl_buffer[mip_map][buffer_offset]);
|
tuple.format, tuple.type, &gl_buffer[mip_map][buffer_offset]);
|
||||||
break;
|
break;
|
||||||
case SurfaceTarget::Texture2DArray:
|
case SurfaceTarget::Texture2DArray:
|
||||||
case SurfaceTarget::TextureCubeArray:
|
case SurfaceTarget::TextureCubeArray:
|
||||||
glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0,
|
glTextureSubImage3D(texture.handle, mip_map, x0, y0, 0,
|
||||||
static_cast<GLsizei>(rect.GetWidth()),
|
static_cast<GLsizei>(rect.GetWidth()),
|
||||||
static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format,
|
static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format,
|
||||||
tuple.type, &gl_buffer[mip_map][buffer_offset]);
|
tuple.type, &gl_buffer[mip_map][buffer_offset]);
|
||||||
break;
|
break;
|
||||||
case SurfaceTarget::TextureCubemap: {
|
case SurfaceTarget::TextureCubemap: {
|
||||||
std::size_t start = buffer_offset;
|
std::size_t start = buffer_offset;
|
||||||
for (std::size_t face = 0; face < params.depth; ++face) {
|
for (std::size_t face = 0; face < params.depth; ++face) {
|
||||||
glTexSubImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), mip_map,
|
glTextureSubImage3D(texture.handle, mip_map, x0, y0, static_cast<GLint>(face),
|
||||||
x0, y0, static_cast<GLsizei>(rect.GetWidth()),
|
static_cast<GLsizei>(rect.GetWidth()),
|
||||||
static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
|
static_cast<GLsizei>(rect.GetHeight()), 1, tuple.format,
|
||||||
&gl_buffer[mip_map][buffer_offset]);
|
tuple.type, &gl_buffer[mip_map][buffer_offset]);
|
||||||
buffer_offset += params.LayerSizeGL(mip_map);
|
buffer_offset += params.LayerSizeGL(mip_map);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -864,9 +833,10 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
|
||||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
|
LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
|
||||||
static_cast<u32>(params.target));
|
static_cast<u32>(params.target));
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, mip_map, x0, y0, static_cast<GLsizei>(rect.GetWidth()),
|
glTextureSubImage2D(texture.handle, mip_map, x0, y0,
|
||||||
static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
|
static_cast<GLsizei>(rect.GetWidth()),
|
||||||
&gl_buffer[mip_map][buffer_offset]);
|
static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
|
||||||
|
&gl_buffer[mip_map][buffer_offset]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -876,29 +846,18 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
|
||||||
void CachedSurface::EnsureTextureView() {
|
void CachedSurface::EnsureTextureView() {
|
||||||
if (texture_view.handle != 0)
|
if (texture_view.handle != 0)
|
||||||
return;
|
return;
|
||||||
// Compressed texture are not being created with immutable storage
|
|
||||||
UNIMPLEMENTED_IF(gl_is_compressed);
|
|
||||||
|
|
||||||
const GLenum target{TargetLayer()};
|
const GLenum target{TargetLayer()};
|
||||||
const GLuint num_layers{target == GL_TEXTURE_CUBE_MAP_ARRAY ? 6u : 1u};
|
const GLuint num_layers{target == GL_TEXTURE_CUBE_MAP_ARRAY ? 6u : 1u};
|
||||||
constexpr GLuint min_layer = 0;
|
constexpr GLuint min_layer = 0;
|
||||||
constexpr GLuint min_level = 0;
|
constexpr GLuint min_level = 0;
|
||||||
|
|
||||||
texture_view.Create();
|
glGenTextures(1, &texture_view.handle);
|
||||||
glTextureView(texture_view.handle, target, texture.handle, gl_internal_format, min_level,
|
glTextureView(texture_view.handle, target, texture.handle, gl_internal_format, 0,
|
||||||
params.max_mip_level, min_layer, num_layers);
|
params.max_mip_level, 0, 1);
|
||||||
|
ApplyTextureDefaults(texture_view.handle, params.max_mip_level);
|
||||||
OpenGLState cur_state = OpenGLState::GetCurState();
|
glTextureParameteriv(texture_view.handle, GL_TEXTURE_SWIZZLE_RGBA,
|
||||||
const auto& old_tex = cur_state.texture_units[0];
|
reinterpret_cast<const GLint*>(swizzle.data()));
|
||||||
SCOPE_EXIT({
|
|
||||||
cur_state.texture_units[0] = old_tex;
|
|
||||||
cur_state.Apply();
|
|
||||||
});
|
|
||||||
cur_state.texture_units[0].texture = texture_view.handle;
|
|
||||||
cur_state.texture_units[0].target = target;
|
|
||||||
cur_state.Apply();
|
|
||||||
|
|
||||||
ApplyTextureDefaults(target, params.max_mip_level);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 192, 64));
|
MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 192, 64));
|
||||||
|
@ -909,6 +868,25 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
|
||||||
UploadGLMipmapTexture(i, read_fb_handle, draw_fb_handle);
|
UploadGLMipmapTexture(i, read_fb_handle, draw_fb_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CachedSurface::UpdateSwizzle(Tegra::Texture::SwizzleSource swizzle_x,
|
||||||
|
Tegra::Texture::SwizzleSource swizzle_y,
|
||||||
|
Tegra::Texture::SwizzleSource swizzle_z,
|
||||||
|
Tegra::Texture::SwizzleSource swizzle_w) {
|
||||||
|
const GLenum new_x = MaxwellToGL::SwizzleSource(swizzle_x);
|
||||||
|
const GLenum new_y = MaxwellToGL::SwizzleSource(swizzle_y);
|
||||||
|
const GLenum new_z = MaxwellToGL::SwizzleSource(swizzle_z);
|
||||||
|
const GLenum new_w = MaxwellToGL::SwizzleSource(swizzle_w);
|
||||||
|
if (swizzle[0] == new_x && swizzle[1] == new_y && swizzle[2] == new_z && swizzle[3] == new_w) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
swizzle = {new_x, new_y, new_z, new_w};
|
||||||
|
const auto swizzle_data = reinterpret_cast<const GLint*>(swizzle.data());
|
||||||
|
glTextureParameteriv(texture.handle, GL_TEXTURE_SWIZZLE_RGBA, swizzle_data);
|
||||||
|
if (texture_view.handle != 0) {
|
||||||
|
glTextureParameteriv(texture_view.handle, GL_TEXTURE_SWIZZLE_RGBA, swizzle_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RasterizerCacheOpenGL::RasterizerCacheOpenGL(RasterizerOpenGL& rasterizer)
|
RasterizerCacheOpenGL::RasterizerCacheOpenGL(RasterizerOpenGL& rasterizer)
|
||||||
: RasterizerCache{rasterizer} {
|
: RasterizerCache{rasterizer} {
|
||||||
read_framebuffer.Create();
|
read_framebuffer.Create();
|
||||||
|
|
|
@ -382,6 +382,11 @@ public:
|
||||||
// Upload data in gl_buffer to this surface's texture
|
// Upload data in gl_buffer to this surface's texture
|
||||||
void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle);
|
void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle);
|
||||||
|
|
||||||
|
void UpdateSwizzle(Tegra::Texture::SwizzleSource swizzle_x,
|
||||||
|
Tegra::Texture::SwizzleSource swizzle_y,
|
||||||
|
Tegra::Texture::SwizzleSource swizzle_z,
|
||||||
|
Tegra::Texture::SwizzleSource swizzle_w);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, GLuint draw_fb_handle);
|
void UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, GLuint draw_fb_handle);
|
||||||
|
|
||||||
|
@ -393,8 +398,8 @@ private:
|
||||||
SurfaceParams params{};
|
SurfaceParams params{};
|
||||||
GLenum gl_target{};
|
GLenum gl_target{};
|
||||||
GLenum gl_internal_format{};
|
GLenum gl_internal_format{};
|
||||||
bool gl_is_compressed{};
|
|
||||||
std::size_t cached_size_in_bytes{};
|
std::size_t cached_size_in_bytes{};
|
||||||
|
std::array<GLenum, 4> swizzle{GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA};
|
||||||
};
|
};
|
||||||
|
|
||||||
class RasterizerCacheOpenGL final : public RasterizerCache<Surface> {
|
class RasterizerCacheOpenGL final : public RasterizerCache<Surface> {
|
||||||
|
|
|
@ -15,12 +15,12 @@ MICROPROFILE_DEFINE(OpenGL_ResourceDeletion, "OpenGL", "Resource Deletion", MP_R
|
||||||
|
|
||||||
namespace OpenGL {
|
namespace OpenGL {
|
||||||
|
|
||||||
void OGLTexture::Create() {
|
void OGLTexture::Create(GLenum target) {
|
||||||
if (handle != 0)
|
if (handle != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
|
MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
|
||||||
glGenTextures(1, &handle);
|
glCreateTextures(target, 1, &handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OGLTexture::Release() {
|
void OGLTexture::Release() {
|
||||||
|
|
|
@ -28,7 +28,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new internal OpenGL resource and stores the handle
|
/// Creates a new internal OpenGL resource and stores the handle
|
||||||
void Create();
|
void Create(GLenum target);
|
||||||
|
|
||||||
/// Deletes the internal OpenGL resource
|
/// Deletes the internal OpenGL resource
|
||||||
void Release();
|
void Release();
|
||||||
|
|
|
@ -462,29 +462,35 @@ void OpenGLState::ApplyPolygonOffset() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLState::ApplyTextures() const {
|
void OpenGLState::ApplyTextures() const {
|
||||||
|
bool has_delta{};
|
||||||
|
std::size_t first{};
|
||||||
|
std::size_t last{};
|
||||||
|
std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> textures;
|
||||||
|
|
||||||
for (std::size_t i = 0; i < std::size(texture_units); ++i) {
|
for (std::size_t i = 0; i < std::size(texture_units); ++i) {
|
||||||
const auto& texture_unit = texture_units[i];
|
const auto& texture_unit = texture_units[i];
|
||||||
const auto& cur_state_texture_unit = cur_state.texture_units[i];
|
const auto& cur_state_texture_unit = cur_state.texture_units[i];
|
||||||
|
textures[i] = texture_unit.texture;
|
||||||
|
|
||||||
if (texture_unit.texture != cur_state_texture_unit.texture) {
|
if (textures[i] != cur_state_texture_unit.texture) {
|
||||||
glActiveTexture(TextureUnits::MaxwellTexture(static_cast<int>(i)).Enum());
|
if (!has_delta) {
|
||||||
glBindTexture(texture_unit.target, texture_unit.texture);
|
first = i;
|
||||||
}
|
has_delta = true;
|
||||||
// Update the texture swizzle
|
}
|
||||||
if (texture_unit.swizzle.r != cur_state_texture_unit.swizzle.r ||
|
last = i;
|
||||||
texture_unit.swizzle.g != cur_state_texture_unit.swizzle.g ||
|
|
||||||
texture_unit.swizzle.b != cur_state_texture_unit.swizzle.b ||
|
|
||||||
texture_unit.swizzle.a != cur_state_texture_unit.swizzle.a) {
|
|
||||||
std::array<GLint, 4> mask = {texture_unit.swizzle.r, texture_unit.swizzle.g,
|
|
||||||
texture_unit.swizzle.b, texture_unit.swizzle.a};
|
|
||||||
glTexParameteriv(texture_unit.target, GL_TEXTURE_SWIZZLE_RGBA, mask.data());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (has_delta) {
|
||||||
|
glBindTextures(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1),
|
||||||
|
textures.data());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLState::ApplySamplers() const {
|
void OpenGLState::ApplySamplers() const {
|
||||||
bool has_delta{};
|
bool has_delta{};
|
||||||
std::size_t first{}, last{};
|
std::size_t first{};
|
||||||
|
std::size_t last{};
|
||||||
std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers;
|
std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers;
|
||||||
for (std::size_t i = 0; i < std::size(samplers); ++i) {
|
for (std::size_t i = 0; i < std::size(samplers); ++i) {
|
||||||
samplers[i] = texture_units[i].sampler;
|
samplers[i] = texture_units[i].sampler;
|
||||||
|
|
|
@ -126,26 +126,14 @@ public:
|
||||||
struct TextureUnit {
|
struct TextureUnit {
|
||||||
GLuint texture; // GL_TEXTURE_BINDING_2D
|
GLuint texture; // GL_TEXTURE_BINDING_2D
|
||||||
GLuint sampler; // GL_SAMPLER_BINDING
|
GLuint sampler; // GL_SAMPLER_BINDING
|
||||||
GLenum target;
|
|
||||||
struct {
|
|
||||||
GLint r; // GL_TEXTURE_SWIZZLE_R
|
|
||||||
GLint g; // GL_TEXTURE_SWIZZLE_G
|
|
||||||
GLint b; // GL_TEXTURE_SWIZZLE_B
|
|
||||||
GLint a; // GL_TEXTURE_SWIZZLE_A
|
|
||||||
} swizzle;
|
|
||||||
|
|
||||||
void Unbind() {
|
void Unbind() {
|
||||||
texture = 0;
|
texture = 0;
|
||||||
swizzle.r = GL_RED;
|
|
||||||
swizzle.g = GL_GREEN;
|
|
||||||
swizzle.b = GL_BLUE;
|
|
||||||
swizzle.a = GL_ALPHA;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reset() {
|
void Reset() {
|
||||||
Unbind();
|
Unbind();
|
||||||
sampler = 0;
|
sampler = 0;
|
||||||
target = GL_TEXTURE_2D;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
std::array<TextureUnit, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> texture_units;
|
std::array<TextureUnit, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> texture_units;
|
||||||
|
|
|
@ -171,10 +171,6 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
|
||||||
Memory::GetPointer(framebuffer_addr),
|
Memory::GetPointer(framebuffer_addr),
|
||||||
gl_framebuffer_data.data(), true);
|
gl_framebuffer_data.data(), true);
|
||||||
|
|
||||||
state.texture_units[0].texture = screen_info.texture.resource.handle;
|
|
||||||
state.Apply();
|
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride));
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride));
|
||||||
|
|
||||||
// Update existing texture
|
// Update existing texture
|
||||||
|
@ -182,14 +178,11 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
|
||||||
// they differ from the LCD resolution.
|
// they differ from the LCD resolution.
|
||||||
// TODO: Applications could theoretically crash yuzu here by specifying too large
|
// TODO: Applications could theoretically crash yuzu here by specifying too large
|
||||||
// framebuffer sizes. We should make sure that this cannot happen.
|
// framebuffer sizes. We should make sure that this cannot happen.
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer.width, framebuffer.height,
|
glTextureSubImage2D(screen_info.texture.resource.handle, 0, 0, 0, framebuffer.width,
|
||||||
screen_info.texture.gl_format, screen_info.texture.gl_type,
|
framebuffer.height, screen_info.texture.gl_format,
|
||||||
gl_framebuffer_data.data());
|
screen_info.texture.gl_type, gl_framebuffer_data.data());
|
||||||
|
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
|
|
||||||
state.texture_units[0].texture = 0;
|
|
||||||
state.Apply();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,17 +192,8 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
|
||||||
*/
|
*/
|
||||||
void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a,
|
void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a,
|
||||||
const TextureInfo& texture) {
|
const TextureInfo& texture) {
|
||||||
state.texture_units[0].texture = texture.resource.handle;
|
const u8 framebuffer_data[4] = {color_a, color_b, color_g, color_r};
|
||||||
state.Apply();
|
glClearTexImage(texture.resource.handle, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer_data);
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
u8 framebuffer_data[4] = {color_a, color_b, color_g, color_r};
|
|
||||||
|
|
||||||
// Update existing texture
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer_data);
|
|
||||||
|
|
||||||
state.texture_units[0].texture = 0;
|
|
||||||
state.Apply();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -249,26 +233,13 @@ void RendererOpenGL::InitOpenGLObjects() {
|
||||||
sizeof(ScreenRectVertex));
|
sizeof(ScreenRectVertex));
|
||||||
|
|
||||||
// Allocate textures for the screen
|
// Allocate textures for the screen
|
||||||
screen_info.texture.resource.Create();
|
screen_info.texture.resource.Create(GL_TEXTURE_2D);
|
||||||
|
|
||||||
// Allocation of storage is deferred until the first frame, when we
|
const GLuint texture = screen_info.texture.resource.handle;
|
||||||
// know the framebuffer size.
|
glTextureStorage2D(texture, 1, GL_RGBA8, 1, 1);
|
||||||
|
|
||||||
state.texture_units[0].texture = screen_info.texture.resource.handle;
|
|
||||||
state.Apply();
|
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
|
|
||||||
screen_info.display_texture = screen_info.texture.resource.handle;
|
screen_info.display_texture = screen_info.texture.resource.handle;
|
||||||
|
|
||||||
state.texture_units[0].texture = 0;
|
|
||||||
state.Apply();
|
|
||||||
|
|
||||||
// Clear screen to black
|
// Clear screen to black
|
||||||
LoadColorToActiveGLTexture(0, 0, 0, 0, screen_info.texture);
|
LoadColorToActiveGLTexture(0, 0, 0, 0, screen_info.texture);
|
||||||
}
|
}
|
||||||
|
@ -284,20 +255,19 @@ void RendererOpenGL::CreateRasterizer() {
|
||||||
|
|
||||||
void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
|
void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
|
||||||
const Tegra::FramebufferConfig& framebuffer) {
|
const Tegra::FramebufferConfig& framebuffer) {
|
||||||
|
|
||||||
texture.width = framebuffer.width;
|
texture.width = framebuffer.width;
|
||||||
texture.height = framebuffer.height;
|
texture.height = framebuffer.height;
|
||||||
|
|
||||||
GLint internal_format;
|
GLint internal_format;
|
||||||
switch (framebuffer.pixel_format) {
|
switch (framebuffer.pixel_format) {
|
||||||
case Tegra::FramebufferConfig::PixelFormat::ABGR8:
|
case Tegra::FramebufferConfig::PixelFormat::ABGR8:
|
||||||
internal_format = GL_RGBA;
|
internal_format = GL_RGBA8;
|
||||||
texture.gl_format = GL_RGBA;
|
texture.gl_format = GL_RGBA;
|
||||||
texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
|
texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
|
||||||
gl_framebuffer_data.resize(texture.width * texture.height * 4);
|
gl_framebuffer_data.resize(texture.width * texture.height * 4);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
internal_format = GL_RGBA;
|
internal_format = GL_RGBA8;
|
||||||
texture.gl_format = GL_RGBA;
|
texture.gl_format = GL_RGBA;
|
||||||
texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
|
texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
|
||||||
gl_framebuffer_data.resize(texture.width * texture.height * 4);
|
gl_framebuffer_data.resize(texture.width * texture.height * 4);
|
||||||
|
@ -306,15 +276,9 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
state.texture_units[0].texture = texture.resource.handle;
|
texture.resource.Release();
|
||||||
state.Apply();
|
texture.resource.Create(GL_TEXTURE_2D);
|
||||||
|
glTextureStorage2D(texture.resource.handle, 1, internal_format, texture.width, texture.height);
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0,
|
|
||||||
texture.gl_format, texture.gl_type, nullptr);
|
|
||||||
|
|
||||||
state.texture_units[0].texture = 0;
|
|
||||||
state.Apply();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x, float y, float w,
|
void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x, float y, float w,
|
||||||
|
@ -356,7 +320,6 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x,
|
||||||
}};
|
}};
|
||||||
|
|
||||||
state.texture_units[0].texture = screen_info.display_texture;
|
state.texture_units[0].texture = screen_info.display_texture;
|
||||||
state.texture_units[0].swizzle = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA};
|
|
||||||
// Workaround brigthness problems in SMO by enabling sRGB in the final output
|
// Workaround brigthness problems in SMO by enabling sRGB in the final output
|
||||||
// if it has been used in the frame. Needed because of this bug in QT: QTBUG-50987
|
// if it has been used in the frame. Needed because of this bug in QT: QTBUG-50987
|
||||||
state.framebuffer_srgb.enabled = OpenGLState::GetsRGBUsed();
|
state.framebuffer_srgb.enabled = OpenGLState::GetsRGBUsed();
|
||||||
|
|
Reference in New Issue