diff options
Diffstat (limited to 'src/video_core')
5 files changed, 105 insertions, 185 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 2b9c4628f..a3c782972 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -18,7 +18,6 @@ #include "video_core/morton.h" #include "video_core/renderer_opengl/gl_rasterizer.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/surface.h" #include "video_core/textures/astc.h" @@ -44,14 +43,14 @@ struct FormatTuple { bool compressed; }; -static void ApplyTextureDefaults(GLenum target, u32 max_mip_level) { - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, max_mip_level - 1); +static void ApplyTextureDefaults(GLuint texture, u32 max_mip_level) { + glTextureParameteri(texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTextureParameteri(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTextureParameteri(texture, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTextureParameteri(texture, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTextureParameteri(texture, GL_TEXTURE_MAX_LEVEL, 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) : params(params), gl_target(SurfaceTargetToGL(params.target)), cached_size_in_bytes(params.size_in_bytes) { - texture.Create(); - const auto& rect{params.GetRect()}; - - // Keep track of previous texture bindings - 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 = texture.handle; - cur_state.texture_units[0].target = SurfaceTargetToGL(params.target); - cur_state.Apply(); - glActiveTexture(GL_TEXTURE0); + texture.Create(gl_target); + + // TODO(Rodrigo): Using params.GetRect() returns a different size than using its Mip*(0) + // alternatives. This signals a bug on those functions. + const auto width = static_cast<GLsizei>(params.MipWidth(0)); + const auto height = static_cast<GLsizei>(params.MipHeight(0)); const auto& format_tuple = GetFormatTuple(params.pixel_format, params.component_type); gl_internal_format = format_tuple.internal_format; - gl_is_compressed = format_tuple.compressed; - if (!format_tuple.compressed) { - // Only pre-create the texture for non-compressed textures. - switch (params.target) { - case SurfaceTarget::Texture1D: - glTexStorage1D(SurfaceTargetToGL(params.target), params.max_mip_level, - format_tuple.internal_format, rect.GetWidth()); - break; - case SurfaceTarget::Texture2D: - case SurfaceTarget::TextureCubemap: - glTexStorage2D(SurfaceTargetToGL(params.target), params.max_mip_level, - format_tuple.internal_format, rect.GetWidth(), rect.GetHeight()); - break; - case SurfaceTarget::Texture3D: - case SurfaceTarget::Texture2DArray: - case SurfaceTarget::TextureCubeArray: - glTexStorage3D(SurfaceTargetToGL(params.target), params.max_mip_level, - format_tuple.internal_format, rect.GetWidth(), rect.GetHeight(), - params.depth); - break; - default: - LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", - static_cast<u32>(params.target)); - UNREACHABLE(); - glTexStorage2D(GL_TEXTURE_2D, params.max_mip_level, format_tuple.internal_format, - rect.GetWidth(), rect.GetHeight()); - } + switch (params.target) { + case SurfaceTarget::Texture1D: + glTextureStorage1D(texture.handle, params.max_mip_level, format_tuple.internal_format, + width); + break; + case SurfaceTarget::Texture2D: + case SurfaceTarget::TextureCubemap: + glTextureStorage2D(texture.handle, params.max_mip_level, format_tuple.internal_format, + width, height); + break; + case SurfaceTarget::Texture3D: + case SurfaceTarget::Texture2DArray: + case SurfaceTarget::TextureCubeArray: + glTextureStorage3D(texture.handle, params.max_mip_level, format_tuple.internal_format, + width, height, params.depth); + break; + default: + LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", + static_cast<u32>(params.target)); + UNREACHABLE(); + glTextureStorage2D(texture.handle, params.max_mip_level, format_tuple.internal_format, + width, height); } - 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()); @@ -752,63 +737,50 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, const auto& rect{params.GetRect(mip_map)}; // Load data from memory to the surface - const GLint x0 = static_cast<GLint>(rect.left); - const GLint y0 = static_cast<GLint>(rect.bottom); - std::size_t buffer_offset = + const auto x0 = static_cast<GLint>(rect.left); + const auto y0 = static_cast<GLint>(rect.bottom); + auto buffer_offset = static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.MipWidth(mip_map) + static_cast<std::size_t>(x0)) * GetBytesPerPixel(params.pixel_format); 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 ASSERT(params.MipWidth(mip_map) * GetBytesPerPixel(params.pixel_format) % 4 == 0); glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.MipWidth(mip_map))); - GLsizei image_size = static_cast<GLsizei>(params.GetMipmapSizeGL(mip_map, false)); - glActiveTexture(GL_TEXTURE0); + const auto image_size = static_cast<GLsizei>(params.GetMipmapSizeGL(mip_map, false)); if (tuple.compressed) { switch (params.target) { case SurfaceTarget::Texture2D: - glCompressedTexImage2D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format, - static_cast<GLsizei>(params.MipWidth(mip_map)), - static_cast<GLsizei>(params.MipHeight(mip_map)), 0, image_size, - &gl_buffer[mip_map][buffer_offset]); + glCompressedTextureSubImage2D( + texture.handle, mip_map, 0, 0, static_cast<GLsizei>(params.MipWidth(mip_map)), + static_cast<GLsizei>(params.MipHeight(mip_map)), tuple.internal_format, image_size, + &gl_buffer[mip_map][buffer_offset]); break; case SurfaceTarget::Texture3D: - glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format, - static_cast<GLsizei>(params.MipWidth(mip_map)), - static_cast<GLsizei>(params.MipHeight(mip_map)), - static_cast<GLsizei>(params.MipDepth(mip_map)), 0, image_size, - &gl_buffer[mip_map][buffer_offset]); + glCompressedTextureSubImage3D( + 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.MipDepth(mip_map)), tuple.internal_format, image_size, + &gl_buffer[mip_map][buffer_offset]); break; case SurfaceTarget::Texture2DArray: case SurfaceTarget::TextureCubeArray: - glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format, - static_cast<GLsizei>(params.MipWidth(mip_map)), - static_cast<GLsizei>(params.MipHeight(mip_map)), - static_cast<GLsizei>(params.depth), 0, image_size, - &gl_buffer[mip_map][buffer_offset]); + glCompressedTextureSubImage3D( + 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.depth), + tuple.internal_format, image_size, &gl_buffer[mip_map][buffer_offset]); break; 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) { - glCompressedTexImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), - mip_map, tuple.internal_format, - static_cast<GLsizei>(params.MipWidth(mip_map)), - static_cast<GLsizei>(params.MipHeight(mip_map)), 0, - layer_size, &gl_buffer[mip_map][buffer_offset]); + glCompressedTextureSubImage3D( + texture.handle, mip_map, 0, 0, static_cast<GLint>(face), + static_cast<GLsizei>(params.MipWidth(mip_map)), + static_cast<GLsizei>(params.MipHeight(mip_map)), 1, tuple.internal_format, + layer_size, &gl_buffer[mip_map][buffer_offset]); buffer_offset += layer_size; } break; @@ -817,46 +789,43 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", static_cast<u32>(params.target)); UNREACHABLE(); - glCompressedTexImage2D(GL_TEXTURE_2D, mip_map, tuple.internal_format, - static_cast<GLsizei>(params.MipWidth(mip_map)), - static_cast<GLsizei>(params.MipHeight(mip_map)), 0, - static_cast<GLsizei>(params.size_in_bytes_gl), - &gl_buffer[mip_map][buffer_offset]); + glCompressedTextureSubImage2D( + texture.handle, mip_map, 0, 0, static_cast<GLsizei>(params.MipWidth(mip_map)), + static_cast<GLsizei>(params.MipHeight(mip_map)), tuple.internal_format, + static_cast<GLsizei>(params.size_in_bytes_gl), &gl_buffer[mip_map][buffer_offset]); } } else { - switch (params.target) { case SurfaceTarget::Texture1D: - glTexSubImage1D(SurfaceTargetToGL(params.target), mip_map, x0, - static_cast<GLsizei>(rect.GetWidth()), tuple.format, tuple.type, - &gl_buffer[mip_map][buffer_offset]); + glTextureSubImage1D(texture.handle, mip_map, x0, static_cast<GLsizei>(rect.GetWidth()), + tuple.format, tuple.type, &gl_buffer[mip_map][buffer_offset]); break; case SurfaceTarget::Texture2D: - glTexSubImage2D(SurfaceTargetToGL(params.target), mip_map, x0, y0, - static_cast<GLsizei>(rect.GetWidth()), - static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, - &gl_buffer[mip_map][buffer_offset]); + glTextureSubImage2D(texture.handle, mip_map, x0, y0, + static_cast<GLsizei>(rect.GetWidth()), + static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, + &gl_buffer[mip_map][buffer_offset]); break; case SurfaceTarget::Texture3D: - glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0, - static_cast<GLsizei>(rect.GetWidth()), - static_cast<GLsizei>(rect.GetHeight()), params.MipDepth(mip_map), - tuple.format, tuple.type, &gl_buffer[mip_map][buffer_offset]); + glTextureSubImage3D(texture.handle, mip_map, x0, y0, 0, + static_cast<GLsizei>(rect.GetWidth()), + static_cast<GLsizei>(rect.GetHeight()), params.MipDepth(mip_map), + tuple.format, tuple.type, &gl_buffer[mip_map][buffer_offset]); break; case SurfaceTarget::Texture2DArray: case SurfaceTarget::TextureCubeArray: - glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0, - static_cast<GLsizei>(rect.GetWidth()), - static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format, - tuple.type, &gl_buffer[mip_map][buffer_offset]); + glTextureSubImage3D(texture.handle, mip_map, x0, y0, 0, + static_cast<GLsizei>(rect.GetWidth()), + static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format, + tuple.type, &gl_buffer[mip_map][buffer_offset]); break; case SurfaceTarget::TextureCubemap: { std::size_t start = buffer_offset; for (std::size_t face = 0; face < params.depth; ++face) { - glTexSubImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), mip_map, - x0, y0, static_cast<GLsizei>(rect.GetWidth()), - static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, - &gl_buffer[mip_map][buffer_offset]); + glTextureSubImage3D(texture.handle, mip_map, x0, y0, static_cast<GLint>(face), + static_cast<GLsizei>(rect.GetWidth()), + static_cast<GLsizei>(rect.GetHeight()), 1, tuple.format, + tuple.type, &gl_buffer[mip_map][buffer_offset]); buffer_offset += params.LayerSizeGL(mip_map); } break; @@ -865,9 +834,10 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", static_cast<u32>(params.target)); UNREACHABLE(); - glTexSubImage2D(GL_TEXTURE_2D, mip_map, x0, y0, static_cast<GLsizei>(rect.GetWidth()), - static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, - &gl_buffer[mip_map][buffer_offset]); + glTextureSubImage2D(texture.handle, mip_map, x0, y0, + static_cast<GLsizei>(rect.GetWidth()), + static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, + &gl_buffer[mip_map][buffer_offset]); } } @@ -877,29 +847,16 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, void CachedSurface::EnsureTextureView() { if (texture_view.handle != 0) return; - // Compressed texture are not being created with immutable storage - UNIMPLEMENTED_IF(gl_is_compressed); const GLenum target{TargetLayer()}; const GLuint num_layers{target == GL_TEXTURE_CUBE_MAP_ARRAY ? 6u : 1u}; constexpr GLuint min_layer = 0; constexpr GLuint min_level = 0; - texture_view.Create(); - glTextureView(texture_view.handle, target, texture.handle, gl_internal_format, min_level, - params.max_mip_level, min_layer, num_layers); - - 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 = texture_view.handle; - cur_state.texture_units[0].target = target; - cur_state.Apply(); - - ApplyTextureDefaults(target, params.max_mip_level); + glGenTextures(1, &texture_view.handle); + glTextureView(texture_view.handle, target, texture.handle, gl_internal_format, 0, + params.max_mip_level, 0, 1); + ApplyTextureDefaults(texture_view.handle, params.max_mip_level); } MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 192, 64)); diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 8d7d6722c..9ee6f3f65 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -393,7 +393,6 @@ private: SurfaceParams params{}; GLenum gl_target{}; GLenum gl_internal_format{}; - bool gl_is_compressed{}; std::size_t cached_size_in_bytes{}; }; diff --git a/src/video_core/renderer_opengl/gl_resource_manager.cpp b/src/video_core/renderer_opengl/gl_resource_manager.cpp index 1da744158..4170cbd3c 100644 --- a/src/video_core/renderer_opengl/gl_resource_manager.cpp +++ b/src/video_core/renderer_opengl/gl_resource_manager.cpp @@ -15,12 +15,12 @@ MICROPROFILE_DEFINE(OpenGL_ResourceDeletion, "OpenGL", "Resource Deletion", MP_R namespace OpenGL { -void OGLTexture::Create() { +void OGLTexture::Create(GLenum target) { if (handle != 0) return; MICROPROFILE_SCOPE(OpenGL_ResourceCreation); - glGenTextures(1, &handle); + glCreateTextures(target, 1, &handle); } void OGLTexture::Release() { diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h index e33f1e973..df76cbc4b 100644 --- a/src/video_core/renderer_opengl/gl_resource_manager.h +++ b/src/video_core/renderer_opengl/gl_resource_manager.h @@ -28,7 +28,7 @@ public: } /// Creates a new internal OpenGL resource and stores the handle - void Create(); + void Create(GLenum target); /// Deletes the internal OpenGL resource void Release(); diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index e37b65b38..761dd6be3 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -171,10 +171,6 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf Memory::GetPointer(framebuffer_addr), 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)); // Update existing texture @@ -182,14 +178,11 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf // they differ from the LCD resolution. // TODO: Applications could theoretically crash yuzu here by specifying too large // framebuffer sizes. We should make sure that this cannot happen. - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer.width, framebuffer.height, - screen_info.texture.gl_format, screen_info.texture.gl_type, - gl_framebuffer_data.data()); + glTextureSubImage2D(screen_info.texture.resource.handle, 0, 0, 0, framebuffer.width, + framebuffer.height, screen_info.texture.gl_format, + screen_info.texture.gl_type, gl_framebuffer_data.data()); 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, const TextureInfo& texture) { - state.texture_units[0].texture = texture.resource.handle; - state.Apply(); - - 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(); + const u8 framebuffer_data[4] = {color_a, color_b, color_g, color_r}; + glClearTexImage(texture.resource.handle, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer_data); } /** @@ -249,26 +233,13 @@ void RendererOpenGL::InitOpenGLObjects() { sizeof(ScreenRectVertex)); // 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 - // know the framebuffer size. - - 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); + const GLuint texture = screen_info.texture.resource.handle; + glTextureStorage2D(texture, 1, GL_RGBA8, 1, 1); screen_info.display_texture = screen_info.texture.resource.handle; - state.texture_units[0].texture = 0; - state.Apply(); - // Clear screen to black LoadColorToActiveGLTexture(0, 0, 0, 0, screen_info.texture); } @@ -284,20 +255,19 @@ void RendererOpenGL::CreateRasterizer() { void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, const Tegra::FramebufferConfig& framebuffer) { - texture.width = framebuffer.width; texture.height = framebuffer.height; GLint internal_format; switch (framebuffer.pixel_format) { case Tegra::FramebufferConfig::PixelFormat::ABGR8: - internal_format = GL_RGBA; + internal_format = GL_RGBA8; texture.gl_format = GL_RGBA; texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; gl_framebuffer_data.resize(texture.width * texture.height * 4); break; default: - internal_format = GL_RGBA; + internal_format = GL_RGBA8; texture.gl_format = GL_RGBA; texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; gl_framebuffer_data.resize(texture.width * texture.height * 4); @@ -306,15 +276,9 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, UNREACHABLE(); } - state.texture_units[0].texture = texture.resource.handle; - state.Apply(); - - 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(); + texture.resource.Release(); + texture.resource.Create(GL_TEXTURE_2D); + glTextureStorage2D(texture.resource.handle, 1, internal_format, texture.width, texture.height); } void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x, float y, float w, |