* format: add internal formats for drm formats cross referenced with weston and added internal formats and types for a lot of missing ones. also added a isFormatYUV helper. * framebuffer: ensure we use right internalformat ensure we use the right internal format to avoid internal driver blitting, also since we only attach the GL_STENCIL_ATTACHMENT we might just aswell only use the GL_STENCIL_INDEX8 to not confuse drivers that we want a depth aswell. * texture: use external on yuv or non linear mods using external makes us use the gpu's internal detiler. and this is makes intel a lot happier then having to format convert it to a linear format internally. * shaders: add external support to CM frag add external support to CM frag, and correct ext.frag typo. * formats: remove duplicates and fix a typo in cm.frag remove duplicate formats and a typo in cm.frag * formats: add swizzle logic to all formats add swizzle logic from weston for all formats and use it in shm texture paths. * format: more format changes use monitor drm format instead of forcing something different. * shader: remove external from cm.frag drivers want this resolved at compiletime cant use both samplerExternalOES and sampler2d and then runtime branch it. * screencopy: swizzle textures in screencopy swizzle textures in screencopy, to get the right colors when copying. * screencopy: restore old behaviour try restore old behaviour before the gles3 format changes. glReadPixels had the wrong format, so i went to far trying to mitigate it. should be like before now.
218 lines
6.6 KiB
C++
218 lines
6.6 KiB
C++
#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);
|
|
}
|
|
|
|
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());
|
|
|
|
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));
|
|
unbind();
|
|
|
|
if (m_keepDataCopy) {
|
|
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;
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
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());
|
|
|
|
damage.copy().intersect(CBox{{}, m_size}).forEachRect([&format, &stride, &pixels](const auto& rect) {
|
|
GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / format->bytesPerBlock));
|
|
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));
|
|
});
|
|
|
|
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 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() {
|
|
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));
|
|
}
|