diff options
| author | UjinT34 <41110182+UjinT34@users.noreply.github.com> | 2026-03-07 00:44:10 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-03-06 21:44:10 +0000 |
| commit | 4152ac76d0813d9d0f67d2f04653a13fa6e17433 (patch) | |
| tree | c341f1883cf5a182d32e4ad00192ba8786a9bb75 /src/render/gl/GLTexture.cpp | |
| parent | a5858018d896e0e0f0db517f893cd9a0936dd881 (diff) | |
renderer: refactor Texture, Framebuffer and Renderbuffer (#13437)
Part 1 of the renderer refactors
Diffstat (limited to 'src/render/gl/GLTexture.cpp')
| -rw-r--r-- | src/render/gl/GLTexture.cpp | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/src/render/gl/GLTexture.cpp b/src/render/gl/GLTexture.cpp new file mode 100644 index 00000000..6a1fb172 --- /dev/null +++ b/src/render/gl/GLTexture.cpp @@ -0,0 +1,223 @@ +#include "GLTexture.hpp" +#include "../Renderer.hpp" +#include "../../Compositor.hpp" +#include "../../helpers/Format.hpp" +#include "render/Texture.hpp" +#include <cstring> + +CGLTexture::CGLTexture(bool opaque) { + m_opaque = opaque; +} + +CGLTexture::~CGLTexture() { + if (!g_pCompositor || g_pCompositor->m_isShuttingDown || !g_pHyprRenderer) + return; + + g_pHyprRenderer->makeEGLCurrent(); + if (m_texID) { + GLCALL(glDeleteTextures(1, &m_texID)); + m_texID = 0; + } + + if (m_eglImage) + g_pHyprOpenGL->m_proc.eglDestroyImageKHR(g_pHyprOpenGL->m_eglDisplay, m_eglImage); + m_eglImage = nullptr; + m_cachedStates.fill(std::nullopt); +} + +CGLTexture::CGLTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_, bool keepDataCopy, bool opaque) : + ITexture(drmFormat, pixels, stride, size_, keepDataCopy, opaque) { + + g_pHyprRenderer->makeEGLCurrent(); + + const auto format = NFormatUtils::getPixelFormatFromDRM(drmFormat); + ASSERT(format); + + m_type = format->withAlpha ? TEXTURE_RGBA : TEXTURE_RGBX; + m_size = size_; + m_isSynchronous = true; + m_target = GL_TEXTURE_2D; + allocate(size_); + bind(); + setTexParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + setTexParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + if (format->swizzle.has_value()) + swizzle(format->swizzle.value()); + + bool alignmentChanged = false; + if (format->bytesPerBlock != 4) { + const GLint alignment = (stride % 4 == 0) ? 4 : 1; + GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, alignment)); + alignmentChanged = true; + } + + GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / format->bytesPerBlock)); + GLCALL(glTexImage2D(GL_TEXTURE_2D, 0, format->glInternalFormat ? format->glInternalFormat : format->glFormat, size_.x, size_.y, 0, format->glFormat, format->glType, pixels)); + GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0)); + if (alignmentChanged) + GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 4)); + + unbind(); +} + +CGLTexture::CGLTexture(const Aquamarine::SDMABUFAttrs& attrs, void* image, bool opaque) { + m_opaque = opaque; + if (!g_pHyprOpenGL->m_proc.glEGLImageTargetTexture2DOES) { + Log::logger->log(Log::ERR, "Cannot create a dmabuf texture: no glEGLImageTargetTexture2DOES"); + return; + } + + m_opaque = NFormatUtils::isFormatOpaque(attrs.format); + + // #TODO external only formats should be external aswell. + // also needs a seperate color shader. + /*if (NFormatUtils::isFormatYUV(attrs.format)) { + m_target = GL_TEXTURE_EXTERNAL_OES; + m_type = TEXTURE_EXTERNAL; + } else {*/ + m_target = GL_TEXTURE_2D; + m_type = NFormatUtils::isFormatOpaque(attrs.format) ? TEXTURE_RGBX : TEXTURE_RGBA; + //} + + allocate(attrs.size); + m_eglImage = image; + + bind(); + setTexParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + setTexParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + GLCALL(g_pHyprOpenGL->m_proc.glEGLImageTargetTexture2DOES(m_target, image)); + unbind(); +} + +CGLTexture::CGLTexture(std::span<const float> lut3D, size_t N) : ITexture(lut3D, N), m_target(GL_TEXTURE_3D) { + allocate({}); + bind(); + + GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); + setTexParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR); + setTexParameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR); + setTexParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + setTexParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + setTexParameter(GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + // Expand RGB->RGBA on upload (alpha=1) + std::vector<float> rgba; + rgba.resize(N * N * N * 4); + for (size_t i = 0, j = 0; i < N * N * N; ++i, j += 3) { + rgba[i * 4 + 0] = lut3D[j + 0]; + rgba[i * 4 + 1] = lut3D[j + 1]; + rgba[i * 4 + 2] = lut3D[j + 2]; + rgba[i * 4 + 3] = 1.F; + } + + GLCALL(glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA16F, N, N, N, 0, GL_RGBA, GL_FLOAT, rgba.data())); + + unbind(); +} + +void CGLTexture::update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage) { + if (damage.empty()) + return; + + g_pHyprRenderer->makeEGLCurrent(); + + const auto format = NFormatUtils::getPixelFormatFromDRM(drmFormat); + ASSERT(format); + + bind(); + + if (format->swizzle.has_value()) + swizzle(format->swizzle.value()); + + bool alignmentChanged = false; + if (format->bytesPerBlock != 4) { + const GLint alignment = (stride % 4 == 0) ? 4 : 1; + GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, alignment)); + alignmentChanged = true; + } + + GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / format->bytesPerBlock)); + + damage.copy().intersect(CBox{{}, m_size}).forEachRect([&format, &pixels](const auto& rect) { + GLCALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, rect.x1)); + GLCALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, rect.y1)); + + int width = rect.x2 - rect.x1; + int height = rect.y2 - rect.y1; + GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x1, rect.y1, width, height, format->glFormat, format->glType, pixels)); + }); + + if (alignmentChanged) + GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 4)); + + GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0)); + GLCALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0)); + GLCALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0)); + + unbind(); + + if (m_keepDataCopy) { + m_dataCopy.resize(stride * m_size.y); + memcpy(m_dataCopy.data(), pixels, stride * m_size.y); + } +} + +void CGLTexture::allocate(const Vector2D& size, uint32_t drmFormat) { + if (!m_texID) + GLCALL(glGenTextures(1, &m_texID)); + m_size = size; + m_drmFormat = drmFormat; +} + +void CGLTexture::bind() { + GLCALL(glBindTexture(m_target, m_texID)); +} + +void CGLTexture::unbind() { + GLCALL(glBindTexture(m_target, 0)); +} + +bool CGLTexture::ok() { + return m_texID > 0; +} + +bool CGLTexture::isDMA() { + return m_eglImage; +} + +constexpr std::optional<size_t> CGLTexture::getCacheStateIndex(GLenum pname) { + switch (pname) { + case GL_TEXTURE_WRAP_S: return TEXTURE_PAR_WRAP_S; + case GL_TEXTURE_WRAP_T: return TEXTURE_PAR_WRAP_T; + case GL_TEXTURE_MAG_FILTER: return TEXTURE_PAR_MAG_FILTER; + case GL_TEXTURE_MIN_FILTER: return TEXTURE_PAR_MIN_FILTER; + case GL_TEXTURE_SWIZZLE_R: return TEXTURE_PAR_SWIZZLE_R; + case GL_TEXTURE_SWIZZLE_B: return TEXTURE_PAR_SWIZZLE_B; + default: return std::nullopt; + } +} + +void CGLTexture::setTexParameter(GLenum pname, GLint param) { + const auto cacheIndex = getCacheStateIndex(pname); + + if (!cacheIndex) { + GLCALL(glTexParameteri(m_target, pname, param)); + return; + } + + const auto idx = cacheIndex.value(); + + if (m_cachedStates[idx] == param) + return; + + m_cachedStates[idx] = param; + GLCALL(glTexParameteri(m_target, pname, param)); +} + +void CGLTexture::swizzle(const std::array<GLint, 4>& colors) { + setTexParameter(GL_TEXTURE_SWIZZLE_R, colors.at(0)); + setTexParameter(GL_TEXTURE_SWIZZLE_G, colors.at(1)); + setTexParameter(GL_TEXTURE_SWIZZLE_B, colors.at(2)); + setTexParameter(GL_TEXTURE_SWIZZLE_A, colors.at(3)); +} |
