renderer: refactor Texture, Framebuffer and Renderbuffer (#13437)
Some checks are pending
Build Hyprland / Build Hyprland (Arch) (push) Waiting to run
Build Hyprland / Code Style (push) Waiting to run
Nix / update-inputs (push) Waiting to run
Nix / hyprland (push) Waiting to run
Nix / xdph (push) Blocked by required conditions
Nix / test (push) Waiting to run
Security Checks / Flawfinder Checks (push) Waiting to run

Part 1 of the renderer refactors
This commit is contained in:
UjinT34 2026-03-07 00:44:10 +03:00 committed by GitHub
parent a5858018d8
commit 4152ac76d0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
46 changed files with 1154 additions and 843 deletions

View file

@ -1,265 +1,24 @@
#include "Texture.hpp"
#include "Renderer.hpp"
#include "../Compositor.hpp"
#include "../protocols/types/Buffer.hpp"
#include "../helpers/Format.hpp"
#include <cstring>
CTexture::CTexture() = default;
CTexture::~CTexture() {
if (!g_pCompositor || g_pCompositor->m_isShuttingDown || !g_pHyprRenderer)
return;
g_pHyprRenderer->makeEGLCurrent();
destroyTexture();
}
CTexture::CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_, bool keepDataCopy) : m_drmFormat(drmFormat), m_keepDataCopy(keepDataCopy) {
createFromShm(drmFormat, pixels, stride, size_);
}
CTexture::CTexture(const Aquamarine::SDMABUFAttrs& attrs, void* image) {
createFromDma(attrs, image);
}
CTexture::CTexture(const SP<Aquamarine::IBuffer> buffer, bool keepDataCopy) : m_keepDataCopy(keepDataCopy) {
if (!buffer)
return;
m_opaque = buffer->opaque;
auto attrs = buffer->dmabuf();
if (!attrs.success) {
// attempt shm
auto shm = buffer->shm();
if (!shm.success) {
Log::logger->log(Log::ERR, "Cannot create a texture: buffer has no dmabuf or shm");
return;
}
auto [pixelData, fmt, bufLen] = buffer->beginDataPtr(0);
m_drmFormat = fmt;
createFromShm(fmt, pixelData, bufLen, shm.size);
return;
}
auto image = g_pHyprOpenGL->createEGLImage(buffer->dmabuf());
if (!image) {
Log::logger->log(Log::ERR, "Cannot create a texture: failed to create an EGLImage");
return;
}
createFromDma(attrs, image);
}
CTexture::CTexture(std::span<const float> lut3D, size_t N) : m_type(TEXTURE_3D_LUT), m_target(GL_TEXTURE_3D), m_size(lut3D.size() / 3, 1), m_isSynchronous(true) {
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 CTexture::createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_) {
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();
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();
if (m_keepDataCopy) {
m_dataCopy.resize(stride * size_.y);
memcpy(m_dataCopy.data(), pixels, stride * size_.y);
ITexture::ITexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy, bool opaque) :
m_size(size), m_opaque(opaque), m_drmFormat(drmFormat), m_keepDataCopy(keepDataCopy) {
if (m_keepDataCopy && stride && pixels) {
m_dataCopy.resize(stride * size.y);
memcpy(m_dataCopy.data(), pixels, stride * size.y);
}
}
void CTexture::createFromDma(const Aquamarine::SDMABUFAttrs& attrs, void* image) {
if (!g_pHyprOpenGL->m_proc.glEGLImageTargetTexture2DOES) {
Log::logger->log(Log::ERR, "Cannot create a dmabuf texture: no glEGLImageTargetTexture2DOES");
return;
}
ITexture::ITexture(std::span<const float> lut3D, size_t N) : m_type(TEXTURE_3D_LUT), m_size(lut3D.size() / 3, 1), m_isSynchronous(true) {}
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;
//}
m_size = attrs.size;
allocate();
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();
bool ITexture::ok() {
return false;
}
void CTexture::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);
}
bool ITexture::isDMA() {
return false;
}
void CTexture::destroyTexture() {
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);
}
void CTexture::allocate() {
if (!m_texID)
GLCALL(glGenTextures(1, &m_texID));
}
const std::vector<uint8_t>& CTexture::dataCopy() {
const std::vector<uint8_t>& ITexture::dataCopy() {
return m_dataCopy;
}
void CTexture::bind() {
GLCALL(glBindTexture(m_target, m_texID));
}
void CTexture::unbind() {
GLCALL(glBindTexture(m_target, 0));
}
constexpr std::optional<size_t> CTexture::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 CTexture::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 CTexture::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));
}