wayland/core: move to new impl (#6268)

* wayland/core/dmabuf: move to new impl

it's the final countdown
This commit is contained in:
Vaxry 2024-06-08 10:07:59 +02:00 committed by GitHub
parent c31d9ef417
commit 6967a31450
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
147 changed files with 5388 additions and 2226 deletions

View file

@ -1,22 +1,26 @@
#include "Framebuffer.hpp"
#include "OpenGL.hpp"
CFramebuffer::CFramebuffer() {
m_cTex = makeShared<CTexture>();
}
bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) {
bool firstAlloc = false;
RASSERT((w > 1 && h > 1), "cannot alloc a FB with negative / zero size! (attempted {}x{})", w, h);
uint32_t glFormat = drmFormatToGL(drmFormat);
uint32_t glType = glFormatToType(glFormat);
uint32_t glFormat = FormatUtils::drmFormatToGL(drmFormat);
uint32_t glType = FormatUtils::glFormatToType(glFormat);
if (m_iFb == (uint32_t)-1) {
firstAlloc = true;
glGenFramebuffers(1, &m_iFb);
}
if (m_cTex.m_iTexID == 0) {
if (m_cTex->m_iTexID == 0) {
firstAlloc = true;
glGenTextures(1, &m_cTex.m_iTexID);
glBindTexture(GL_TEXTURE_2D, m_cTex.m_iTexID);
m_cTex->allocate();
glBindTexture(GL_TEXTURE_2D, m_cTex->m_iTexID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@ -24,11 +28,11 @@ bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) {
}
if (firstAlloc || m_vSize != Vector2D(w, h)) {
glBindTexture(GL_TEXTURE_2D, m_cTex.m_iTexID);
glBindTexture(GL_TEXTURE_2D, m_cTex->m_iTexID);
glTexImage2D(GL_TEXTURE_2D, 0, glFormat, w, h, 0, GL_RGBA, glType, 0);
glBindFramebuffer(GL_FRAMEBUFFER, m_iFb);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_cTex.m_iTexID, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_cTex->m_iTexID, 0);
// TODO: Allow this with gles2
#ifndef GLES2
@ -87,12 +91,9 @@ void CFramebuffer::release() {
if (m_iFb != (uint32_t)-1 && m_iFb)
glDeleteFramebuffers(1, &m_iFb);
if (m_cTex.m_iTexID)
glDeleteTextures(1, &m_cTex.m_iTexID);
m_cTex.m_iTexID = 0;
m_iFb = -1;
m_vSize = Vector2D();
m_cTex->destroyTexture();
m_iFb = -1;
m_vSize = Vector2D();
}
CFramebuffer::~CFramebuffer() {

View file

@ -5,19 +5,20 @@
class CFramebuffer {
public:
CFramebuffer();
~CFramebuffer();
bool alloc(int w, int h, uint32_t format = GL_RGBA);
void addStencil();
void bind();
void release();
void reset();
bool isAllocated();
bool alloc(int w, int h, uint32_t format = GL_RGBA);
void addStencil();
void bind();
void release();
void reset();
bool isAllocated();
Vector2D m_vSize;
Vector2D m_vSize;
CTexture m_cTex;
GLuint m_iFb = -1;
SP<CTexture> m_cTex;
GLuint m_iFb = -1;
CTexture* m_pStencilTex = nullptr;
SP<CTexture> m_pStencilTex;
};

View file

@ -7,6 +7,8 @@
#include "../config/ConfigValue.hpp"
#include "../desktop/LayerSurface.hpp"
#include "../protocols/LayerShell.hpp"
#include "../protocols/core/Compositor.hpp"
#include <xf86drm.h>
inline void loadGLProc(void* pProc, const char* name) {
void* proc = (void*)eglGetProcAddress(name);
@ -21,7 +23,8 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL)),
"Couldn't unset current EGL!");
auto* const EXTENSIONS = (const char*)glGetString(GL_EXTENSIONS);
auto* const EXTENSIONS = (const char*)glGetString(GL_EXTENSIONS);
const std::string EGLEXTENSIONS = (const char*)eglQueryString(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_EXTENSIONS);
RASSERT(EXTENSIONS, "Couldn't retrieve openGL extensions!");
@ -33,12 +36,25 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
Debug::log(LOG, "Using: {}", (char*)glGetString(GL_VERSION));
Debug::log(LOG, "Vendor: {}", (char*)glGetString(GL_VENDOR));
Debug::log(LOG, "Renderer: {}", (char*)glGetString(GL_RENDERER));
Debug::log(LOG, "Supported extensions size: {}", std::count(m_szExtensions.begin(), m_szExtensions.end(), ' '));
Debug::log(LOG, "Supported extensions: ({}) {}", std::count(m_szExtensions.begin(), m_szExtensions.end(), ' '), m_szExtensions);
loadGLProc(&m_sProc.glEGLImageTargetRenderbufferStorageOES, "glEGLImageTargetRenderbufferStorageOES");
loadGLProc(&m_sProc.eglCreateImageKHR, "eglCreateImageKHR");
loadGLProc(&m_sProc.eglDestroyImageKHR, "eglDestroyImageKHR");
loadGLProc(&m_sProc.eglQueryDmaBufFormatsEXT, "eglQueryDmaBufFormatsEXT");
loadGLProc(&m_sProc.eglQueryDmaBufModifiersEXT, "eglQueryDmaBufModifiersEXT");
loadGLProc(&m_sProc.glEGLImageTargetTexture2DOES, "glEGLImageTargetTexture2DOES");
m_sExts.EXT_read_format_bgra = m_szExtensions.contains("GL_EXT_read_format_bgra");
m_sExts.EXT_read_format_bgra = m_szExtensions.contains("GL_EXT_read_format_bgra");
m_sExts.EXT_image_dma_buf_import = EGLEXTENSIONS.contains("EXT_image_dma_buf_import");
m_sExts.EXT_image_dma_buf_import_modifiers = EGLEXTENSIONS.contains("EXT_image_dma_buf_import_modifiers");
RASSERT(m_szExtensions.contains("GL_EXT_texture_format_BGRA8888"), "GL_EXT_texture_format_BGRA8888 support by the GPU driver is required");
if (!m_sExts.EXT_read_format_bgra)
Debug::log(WARN, "Your GPU does not support GL_EXT_read_format_bgra, this may cause issues with texture importing");
if (!m_sExts.EXT_image_dma_buf_import || !m_sExts.EXT_image_dma_buf_import_modifiers)
Debug::log(WARN, "Your GPU does not support DMABUFs, this will possibly cause issues and will take a hit on the performance.");
#ifdef USE_TRACY_GPU
@ -54,6 +70,8 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
Debug::log(WARN, "!RENDERER: Using the legacy GLES2 renderer!");
#endif
initDRMFormats();
static auto P = g_pHookSystem->hookDynamic("preRender", [&](void* self, SCallbackInfo& info, std::any data) { preRender(std::any_cast<CMonitor*>(data)); });
RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!");
@ -61,6 +79,171 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
m_tGlobalTimer.reset();
}
std::vector<uint64_t> CHyprOpenGLImpl::getModsForFormat(EGLint format) {
// TODO: return std::expected when clang supports it
if (!m_sExts.EXT_image_dma_buf_import_modifiers)
return {};
EGLint len = 0;
if (!m_sProc.eglQueryDmaBufModifiersEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), format, 0, nullptr, nullptr, &len)) {
Debug::log(ERR, "EGL: Failed to query mods");
return {};
}
if (len <= 0)
return {};
std::vector<uint64_t> mods;
std::vector<EGLBoolean> external;
mods.resize(len);
external.resize(len);
m_sProc.eglQueryDmaBufModifiersEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), format, len, mods.data(), external.data(), &len);
std::vector<uint64_t> result;
for (size_t i = 0; i < mods.size(); ++i) {
if (external.at(i))
continue;
result.push_back(mods.at(i));
}
return result;
}
void CHyprOpenGLImpl::initDRMFormats() {
const auto DISABLE_MODS = envEnabled("HYPRLAND_EGL_NO_MODIFIERS");
if (DISABLE_MODS)
Debug::log(WARN, "HYPRLAND_EGL_NO_MODIFIERS set, disabling modifiers");
if (!m_sExts.EXT_image_dma_buf_import) {
Debug::log(ERR, "EGL: No dmabuf import, DMABufs will not work.");
return;
}
std::vector<EGLint> formats;
if (!m_sExts.EXT_image_dma_buf_import_modifiers || !m_sProc.eglQueryDmaBufFormatsEXT) {
formats.push_back(DRM_FORMAT_ARGB8888);
formats.push_back(DRM_FORMAT_XRGB8888);
Debug::log(WARN, "EGL: No mod support");
} else {
EGLint len = 0;
m_sProc.eglQueryDmaBufFormatsEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), 0, nullptr, &len);
formats.resize(len);
m_sProc.eglQueryDmaBufFormatsEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), len, formats.data(), &len);
}
if (formats.size() == 0) {
Debug::log(ERR, "EGL: Failed to get formats, DMABufs will not work.");
return;
}
wlr_log(WLR_DEBUG, "Supported DMA-BUF formats:");
std::vector<SDRMFormat> dmaFormats;
for (auto& fmt : formats) {
std::vector<uint64_t> mods;
if (!DISABLE_MODS)
mods = getModsForFormat(fmt);
else
mods = {DRM_FORMAT_MOD_LINEAR};
m_bHasModifiers = m_bHasModifiers || mods.size() > 0;
if (mods.size() == 0)
continue;
dmaFormats.push_back(SDRMFormat{
.format = fmt,
.mods = mods,
});
std::vector<std::pair<uint64_t, std::string>> modifierData;
auto fmtName = drmGetFormatName(fmt);
Debug::log(LOG, "EGL: GPU Supports Format {} (0x{:x})", fmtName ? fmtName : "?unknown?", fmt);
for (auto& mod : mods) {
auto modName = drmGetFormatModifierName(mod);
modifierData.emplace_back(std::make_pair<>(mod, modName ? modName : "?unknown?"));
free(modName);
}
free(fmtName);
mods.clear();
std::sort(modifierData.begin(), modifierData.end(), [](const auto& a, const auto& b) {
if (a.first == 0)
return false;
if (a.second.contains("DCC"))
return false;
return true;
});
for (auto& [m, name] : modifierData) {
Debug::log(LOG, "EGL: | with modifier {} (0x{:x})", name, m);
mods.emplace_back(m);
}
}
Debug::log(LOG, "EGL: {} formats found in total. Some modifiers may be omitted as they are external-only.", dmaFormats.size());
drmFormats = dmaFormats;
}
EGLImageKHR CHyprOpenGLImpl::createEGLImage(const SDMABUFAttrs& attrs) {
std::vector<uint32_t> attribs;
attribs.push_back(EGL_WIDTH);
attribs.push_back(attrs.size.x);
attribs.push_back(EGL_HEIGHT);
attribs.push_back(attrs.size.y);
attribs.push_back(EGL_LINUX_DRM_FOURCC_EXT);
attribs.push_back(attrs.format);
struct {
EGLint fd;
EGLint offset;
EGLint pitch;
EGLint modlo;
EGLint modhi;
} attrNames[4] = {
{EGL_DMA_BUF_PLANE0_FD_EXT, EGL_DMA_BUF_PLANE0_OFFSET_EXT, EGL_DMA_BUF_PLANE0_PITCH_EXT, EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT},
{EGL_DMA_BUF_PLANE1_FD_EXT, EGL_DMA_BUF_PLANE1_OFFSET_EXT, EGL_DMA_BUF_PLANE1_PITCH_EXT, EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT},
{EGL_DMA_BUF_PLANE2_FD_EXT, EGL_DMA_BUF_PLANE2_OFFSET_EXT, EGL_DMA_BUF_PLANE2_PITCH_EXT, EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT},
{EGL_DMA_BUF_PLANE3_FD_EXT, EGL_DMA_BUF_PLANE3_OFFSET_EXT, EGL_DMA_BUF_PLANE3_PITCH_EXT, EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT}};
for (int i = 0; i < attrs.planes; i++) {
attribs.push_back(attrNames[i].fd);
attribs.push_back(attrs.fds[i]);
attribs.push_back(attrNames[i].offset);
attribs.push_back(attrs.offsets[i]);
attribs.push_back(attrNames[i].pitch);
attribs.push_back(attrs.strides[i]);
if (m_bHasModifiers && attrs.modifier != DRM_FORMAT_MOD_INVALID) {
attribs.push_back(attrNames[i].modlo);
attribs.push_back(attrs.modifier & 0xFFFFFFFF);
attribs.push_back(attrNames[i].modhi);
attribs.push_back(attrs.modifier >> 32);
}
}
attribs.push_back(EGL_IMAGE_PRESERVED_KHR);
attribs.push_back(EGL_TRUE);
attribs.push_back(EGL_NONE);
EGLImageKHR image = m_sProc.eglCreateImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, (int*)attribs.data());
if (image == EGL_NO_IMAGE_KHR) {
Debug::log(ERR, "EGL: EGLCreateImageKHR failed: {}", eglGetError());
return EGL_NO_IMAGE_KHR;
}
return image;
}
void CHyprOpenGLImpl::logShaderError(const GLuint& shader, bool program) {
GLint maxLength = 0;
if (program)
@ -339,12 +522,12 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebu
// ensure a framebuffer for the monitor exists
if (m_RenderData.pCurrentMonData->offloadFB.m_vSize != pMonitor->vecPixelSize) {
m_RenderData.pCurrentMonData->stencilTex.allocate();
m_RenderData.pCurrentMonData->stencilTex->allocate();
m_RenderData.pCurrentMonData->offloadFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex;
m_RenderData.pCurrentMonData->mirrorFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex;
m_RenderData.pCurrentMonData->mirrorSwapFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex;
m_RenderData.pCurrentMonData->offMainFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex;
m_RenderData.pCurrentMonData->offloadFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex;
m_RenderData.pCurrentMonData->mirrorFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex;
m_RenderData.pCurrentMonData->mirrorSwapFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex;
m_RenderData.pCurrentMonData->offMainFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex;
m_RenderData.pCurrentMonData->offloadFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
m_RenderData.pCurrentMonData->mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
@ -381,8 +564,8 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebu
// we can render to the rbo / fbo (fake) directly
const auto PFBO = fb ? fb : PRBO->getFB();
m_RenderData.currentFB = PFBO;
if (PFBO->m_pStencilTex != &m_RenderData.pCurrentMonData->stencilTex) {
PFBO->m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex;
if (PFBO->m_pStencilTex != m_RenderData.pCurrentMonData->stencilTex) {
PFBO->m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex;
PFBO->addStencil();
}
PFBO->bind();
@ -863,19 +1046,7 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion
scissor((CBox*)nullptr);
}
void CHyprOpenGLImpl::renderTexture(wlr_texture* tex, CBox* pBox, float alpha, int round, bool allowCustomUV) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
renderTexture(CTexture(tex), pBox, alpha, round, false, allowCustomUV);
}
void CHyprOpenGLImpl::renderTextureWithDamage(wlr_texture* tex, CBox* pBox, CRegion* damage, float alpha, int round, bool allowCustomUV) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
renderTextureWithDamage(CTexture(tex), pBox, damage, alpha, round, false, allowCustomUV);
}
void CHyprOpenGLImpl::renderTexture(const CTexture& tex, CBox* pBox, float alpha, int round, bool discardActive, bool allowCustomUV) {
void CHyprOpenGLImpl::renderTexture(SP<CTexture> tex, CBox* pBox, float alpha, int round, bool discardActive, bool allowCustomUV) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
renderTextureInternalWithDamage(tex, pBox, alpha, &m_RenderData.damage, round, discardActive, false, allowCustomUV, true);
@ -883,7 +1054,7 @@ void CHyprOpenGLImpl::renderTexture(const CTexture& tex, CBox* pBox, float alpha
scissor((CBox*)nullptr);
}
void CHyprOpenGLImpl::renderTextureWithDamage(const CTexture& tex, CBox* pBox, CRegion* damage, float alpha, int round, bool discardActive, bool allowCustomUV) {
void CHyprOpenGLImpl::renderTextureWithDamage(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, int round, bool discardActive, bool allowCustomUV) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
renderTextureInternalWithDamage(tex, pBox, alpha, damage, round, discardActive, false, allowCustomUV, true);
@ -891,10 +1062,10 @@ void CHyprOpenGLImpl::renderTextureWithDamage(const CTexture& tex, CBox* pBox, C
scissor((CBox*)nullptr);
}
void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox* pBox, float alpha, CRegion* damage, int round, bool discardActive, bool noAA, bool allowCustomUV,
void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, CBox* pBox, float alpha, CRegion* damage, int round, bool discardActive, bool noAA, bool allowCustomUV,
bool allowDim) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!");
RASSERT((tex->m_iTexID > 0), "Attempted to draw NULL texture!");
TRACY_GPU_ZONE("RenderTextureInternalWithDamage");
@ -934,11 +1105,11 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox*
shader = &m_RenderData.pCurrentMonData->m_shPASSTHRURGBA;
usingFinalShader = true;
} else {
switch (tex.m_iType) {
switch (tex->m_iType) {
case TEXTURE_RGBA: shader = &m_RenderData.pCurrentMonData->m_shRGBA; break;
case TEXTURE_RGBX: shader = &m_RenderData.pCurrentMonData->m_shRGBX; break;
case TEXTURE_EXTERNAL: shader = &m_RenderData.pCurrentMonData->m_shEXT; break;
default: RASSERT(false, "tex.m_iTarget unsupported!");
default: RASSERT(false, "tex->m_iTarget unsupported!");
}
}
}
@ -947,14 +1118,14 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox*
shader = &m_RenderData.pCurrentMonData->m_shRGBX;
glActiveTexture(GL_TEXTURE0);
glBindTexture(tex.m_iTarget, tex.m_iTexID);
glBindTexture(tex->m_iTarget, tex->m_iTexID);
if (m_RenderData.useNearestNeighbor) {
glTexParameteri(tex.m_iTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(tex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(tex->m_iTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(tex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
} else {
glTexParameteri(tex.m_iTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(tex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(tex->m_iTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(tex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
glUseProgram(shader->program);
@ -1057,12 +1228,12 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox*
glDisableVertexAttribArray(shader->posAttrib);
glDisableVertexAttribArray(shader->texAttrib);
glBindTexture(tex.m_iTarget, 0);
glBindTexture(tex->m_iTarget, 0);
}
void CHyprOpenGLImpl::renderTexturePrimitive(const CTexture& tex, CBox* pBox) {
void CHyprOpenGLImpl::renderTexturePrimitive(SP<CTexture> tex, CBox* pBox) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!");
RASSERT((tex->m_iTexID > 0), "Attempted to draw NULL texture!");
TRACY_GPU_ZONE("RenderTexturePrimitive");
@ -1083,7 +1254,7 @@ void CHyprOpenGLImpl::renderTexturePrimitive(const CTexture& tex, CBox* pBox) {
CShader* shader = &m_RenderData.pCurrentMonData->m_shPASSTHRURGBA;
glActiveTexture(GL_TEXTURE0);
glBindTexture(tex.m_iTarget, tex.m_iTexID);
glBindTexture(tex->m_iTarget, tex->m_iTexID);
glUseProgram(shader->program);
@ -1111,12 +1282,12 @@ void CHyprOpenGLImpl::renderTexturePrimitive(const CTexture& tex, CBox* pBox) {
glDisableVertexAttribArray(shader->posAttrib);
glDisableVertexAttribArray(shader->texAttrib);
glBindTexture(tex.m_iTarget, 0);
glBindTexture(tex->m_iTarget, 0);
}
void CHyprOpenGLImpl::renderTextureMatte(const CTexture& tex, CBox* pBox, CFramebuffer& matte) {
void CHyprOpenGLImpl::renderTextureMatte(SP<CTexture> tex, CBox* pBox, CFramebuffer& matte) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!");
RASSERT((tex->m_iTexID > 0), "Attempted to draw NULL texture!");
TRACY_GPU_ZONE("RenderTextureMatte");
@ -1148,10 +1319,10 @@ void CHyprOpenGLImpl::renderTextureMatte(const CTexture& tex, CBox* pBox, CFrame
glUniform1i(shader->alphaMatte, 1);
glActiveTexture(GL_TEXTURE0);
glBindTexture(tex.m_iTarget, tex.m_iTexID);
glBindTexture(tex->m_iTarget, tex->m_iTexID);
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(matte.m_cTex.m_iTarget, matte.m_cTex.m_iTexID);
glBindTexture(matte.m_cTex->m_iTarget, matte.m_cTex->m_iTexID);
glVertexAttribPointer(shader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glVertexAttribPointer(shader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
@ -1169,7 +1340,7 @@ void CHyprOpenGLImpl::renderTextureMatte(const CTexture& tex, CBox* pBox, CFrame
glDisableVertexAttribArray(shader->posAttrib);
glDisableVertexAttribArray(shader->texAttrib);
glBindTexture(tex.m_iTarget, 0);
glBindTexture(tex->m_iTarget, 0);
}
// This probably isn't the fastest
@ -1221,9 +1392,9 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
glActiveTexture(GL_TEXTURE0);
glBindTexture(m_RenderData.currentFB->m_cTex.m_iTarget, m_RenderData.currentFB->m_cTex.m_iTexID);
glBindTexture(m_RenderData.currentFB->m_cTex->m_iTarget, m_RenderData.currentFB->m_cTex->m_iTexID);
glTexParameteri(m_RenderData.currentFB->m_cTex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(m_RenderData.currentFB->m_cTex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glUseProgram(m_RenderData.pCurrentMonData->m_shBLURPREPARE.program);
@ -1265,9 +1436,9 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
glActiveTexture(GL_TEXTURE0);
glBindTexture(currentRenderToFB->m_cTex.m_iTarget, currentRenderToFB->m_cTex.m_iTexID);
glBindTexture(currentRenderToFB->m_cTex->m_iTarget, currentRenderToFB->m_cTex->m_iTexID);
glTexParameteri(currentRenderToFB->m_cTex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(currentRenderToFB->m_cTex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glUseProgram(pShader->program);
@ -1315,7 +1486,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
// draw the things.
// first draw is swap -> mirr
PMIRRORFB->bind();
glBindTexture(PMIRRORSWAPFB->m_cTex.m_iTarget, PMIRRORSWAPFB->m_cTex.m_iTexID);
glBindTexture(PMIRRORSWAPFB->m_cTex->m_iTarget, PMIRRORSWAPFB->m_cTex->m_iTexID);
// damage region will be scaled, make a temp
CRegion tempDamage{damage};
@ -1343,9 +1514,9 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
glActiveTexture(GL_TEXTURE0);
glBindTexture(currentRenderToFB->m_cTex.m_iTarget, currentRenderToFB->m_cTex.m_iTexID);
glBindTexture(currentRenderToFB->m_cTex->m_iTarget, currentRenderToFB->m_cTex->m_iTexID);
glTexParameteri(currentRenderToFB->m_cTex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(currentRenderToFB->m_cTex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glUseProgram(m_RenderData.pCurrentMonData->m_shBLURFINISH.program);
@ -1383,7 +1554,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
}
// finish
glBindTexture(PMIRRORFB->m_cTex.m_iTarget, 0);
glBindTexture(PMIRRORFB->m_cTex->m_iTarget, 0);
blend(BLENDBEFORE);
@ -1417,23 +1588,23 @@ void CHyprOpenGLImpl::preRender(CMonitor* pMonitor) {
if (pWindow->m_sAdditionalConfigData.forceNoBlur)
return false;
if (pWindow->m_pWLSurface.small() && !pWindow->m_pWLSurface.m_bFillIgnoreSmall)
if (pWindow->m_pWLSurface->small() && !pWindow->m_pWLSurface->m_bFillIgnoreSmall)
return true;
const auto PSURFACE = pWindow->m_pWLSurface.wlr();
const auto PSURFACE = pWindow->m_pWLSurface->resource();
const auto PWORKSPACE = pWindow->m_pWorkspace;
const float A = pWindow->m_fAlpha.value() * pWindow->m_fActiveInactiveAlpha.value() * PWORKSPACE->m_fAlpha.value();
if (A >= 1.f) {
if (PSURFACE->opaque)
return false;
// if (PSURFACE->opaque)
// return false;
CRegion inverseOpaque;
pixman_box32_t surfbox = {0, 0, PSURFACE->current.width, PSURFACE->current.height};
CRegion opaqueRegion{&PSURFACE->current.opaque};
inverseOpaque.set(opaqueRegion).invert(&surfbox).intersect(0, 0, PSURFACE->current.width, PSURFACE->current.height);
pixman_box32_t surfbox = {0, 0, PSURFACE->current.size.x, PSURFACE->current.size.y};
CRegion opaqueRegion{PSURFACE->current.opaque};
inverseOpaque.set(opaqueRegion).invert(&surfbox).intersect(0, 0, PSURFACE->current.size.x, PSURFACE->current.size.y);
if (inverseOpaque.empty())
return false;
@ -1461,8 +1632,8 @@ void CHyprOpenGLImpl::preRender(CMonitor* pMonitor) {
if (!ls->layerSurface || ls->xray != 1)
continue;
if (ls->layerSurface->surface->opaque && ls->alpha.value() >= 1.f)
continue;
// if (ls->layerSurface->surface->opaque && ls->alpha.value() >= 1.f)
// continue;
hasWindows = true;
break;
@ -1527,7 +1698,7 @@ bool CHyprOpenGLImpl::shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWin
static auto PBLURNEWOPTIMIZE = CConfigValue<Hyprlang::INT>("decoration:blur:new_optimizations");
static auto PBLURXRAY = CConfigValue<Hyprlang::INT>("decoration:blur:xray");
if (!m_RenderData.pCurrentMonData->blurFB.m_cTex.m_iTexID)
if (!m_RenderData.pCurrentMonData->blurFB.m_cTex->m_iTexID)
return false;
if (pWindow && pWindow->m_sAdditionalConfigData.xray.toUnderlying() == 0)
@ -1545,7 +1716,7 @@ bool CHyprOpenGLImpl::shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWin
return false;
}
void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, CBox* pBox, float a, wlr_surface* pSurface, int round, bool blockBlurOptimization, float blurA) {
void CHyprOpenGLImpl::renderTextureWithBlur(SP<CTexture> tex, CBox* pBox, float a, SP<CWLSurfaceResource> pSurface, int round, bool blockBlurOptimization, float blurA) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture with blur without begin()!");
static auto PBLURENABLED = CConfigValue<Hyprlang::INT>("decoration:blur:enabled");
@ -1570,11 +1741,11 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, CBox* pBox, flo
// amazing hack: the surface has an opaque region!
CRegion inverseOpaque;
if (a >= 1.f && std::round(pSurface->current.width * m_RenderData.pMonitor->scale) == pBox->w &&
std::round(pSurface->current.height * m_RenderData.pMonitor->scale) == pBox->h) {
pixman_box32_t surfbox = {0, 0, pSurface->current.width * pSurface->current.scale, pSurface->current.height * pSurface->current.scale};
inverseOpaque = &pSurface->current.opaque;
inverseOpaque.invert(&surfbox).intersect(0, 0, pSurface->current.width * pSurface->current.scale, pSurface->current.height * pSurface->current.scale);
if (a >= 1.f && std::round(pSurface->current.size.x * m_RenderData.pMonitor->scale) == pBox->w &&
std::round(pSurface->current.size.y * m_RenderData.pMonitor->scale) == pBox->h) {
pixman_box32_t surfbox = {0, 0, pSurface->current.size.x * pSurface->current.scale, pSurface->current.size.y * pSurface->current.scale};
inverseOpaque = pSurface->current.opaque;
inverseOpaque.invert(&surfbox).intersect(0, 0, pSurface->current.size.x * pSurface->current.scale, pSurface->current.size.y * pSurface->current.scale);
if (inverseOpaque.empty()) {
renderTexture(tex, pBox, a, round, false, true);
@ -1765,7 +1936,7 @@ void CHyprOpenGLImpl::makeRawWindowSnapshot(PHLWINDOW pWindow, CFramebuffer* pFr
g_pHyprRenderer->makeEGLCurrent();
pFramebuffer->m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex;
pFramebuffer->m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex;
pFramebuffer->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->drmFormat);
@ -1903,7 +2074,7 @@ void CHyprOpenGLImpl::renderSnapshot(PHLWINDOW pWindow) {
const auto FBDATA = &m_mWindowFramebuffers.at(ref);
if (!FBDATA->m_cTex.m_iTexID)
if (!FBDATA->m_cTex->m_iTexID)
return;
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
@ -1942,7 +2113,7 @@ void CHyprOpenGLImpl::renderSnapshot(PHLLS pLayer) {
const auto FBDATA = &m_mLayerFramebuffers.at(pLayer);
if (!FBDATA->m_cTex.m_iTexID)
if (!FBDATA->m_cTex->m_iTexID)
return;
const auto PMONITOR = g_pCompositor->getMonitorFromID(pLayer->monitorID);
@ -2077,7 +2248,7 @@ void CHyprOpenGLImpl::renderMirrored() {
monbox.y = (monitor->vecTransformedSize.y - monbox.h) / 2;
const auto PFB = &m_mMonitorRenderResources[mirrored].monitorMirrorFB;
if (!PFB->isAllocated() || PFB->m_cTex.m_iTexID <= 0)
if (!PFB->isAllocated() || PFB->m_cTex->m_iTexID <= 0)
return;
// replace monitor projection to undo the mirrored monitor's projection
@ -2179,12 +2350,12 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) {
}
// create a new one with cairo
CTexture tex;
SP<CTexture> tex = makeShared<CTexture>();
const auto CAIROISURFACE = cairo_image_surface_create_from_png(texPath.c_str());
const auto CAIROFORMAT = cairo_image_surface_get_format(CAIROISURFACE);
const auto CAIROISURFACE = cairo_image_surface_create_from_png(texPath.c_str());
const auto CAIROFORMAT = cairo_image_surface_get_format(CAIROISURFACE);
tex.allocate();
tex->allocate();
const Vector2D IMAGESIZE = {cairo_image_surface_get_width(CAIROISURFACE), cairo_image_surface_get_height(CAIROISURFACE)};
// calc the target box
@ -2220,8 +2391,8 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) {
cairo_surface_flush(CAIROSURFACE);
CBox box = {origin.x, origin.y, IMAGESIZE.x * scale, IMAGESIZE.y * scale};
tex.m_vSize = IMAGESIZE * scale;
CBox box = {origin.x, origin.y, IMAGESIZE.x * scale, IMAGESIZE.y * scale};
tex->m_vSize = IMAGESIZE * scale;
// copy the data to an OpenGL texture we have
const GLint glIFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ?
@ -2235,7 +2406,7 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) {
const GLint glType = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_FLOAT : GL_UNSIGNED_BYTE;
const auto DATA = cairo_image_surface_get_data(CAIROSURFACE);
glBindTexture(GL_TEXTURE_2D, tex.m_iTexID);
glBindTexture(GL_TEXTURE_2D, tex->m_iTexID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
#ifndef GLES2
@ -2244,7 +2415,7 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
}
#endif
glTexImage2D(GL_TEXTURE_2D, 0, glIFormat, tex.m_vSize.x, tex.m_vSize.y, 0, glFormat, glType, DATA);
glTexImage2D(GL_TEXTURE_2D, 0, glIFormat, tex->m_vSize.x, tex->m_vSize.y, 0, glFormat, glType, DATA);
cairo_surface_destroy(CAIROSURFACE);
cairo_surface_destroy(CAIROISURFACE);
@ -2293,7 +2464,7 @@ void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) {
RESIT->second.monitorMirrorFB.release();
RESIT->second.blurFB.release();
RESIT->second.offMainFB.release();
RESIT->second.stencilTex.destroyTexture();
RESIT->second.stencilTex->destroyTexture();
g_pHyprOpenGL->m_mMonitorRenderResources.erase(RESIT);
}
@ -2343,109 +2514,6 @@ void CHyprOpenGLImpl::setRenderModifEnabled(bool enabled) {
m_RenderData.renderModif.enabled = enabled;
}
inline const SGLPixelFormat GLES2_FORMATS[] = {
{
.drmFormat = DRM_FORMAT_ARGB8888,
.glFormat = GL_BGRA_EXT,
.glType = GL_UNSIGNED_BYTE,
.withAlpha = true,
},
{
.drmFormat = DRM_FORMAT_XRGB8888,
.glFormat = GL_BGRA_EXT,
.glType = GL_UNSIGNED_BYTE,
.withAlpha = false,
},
{
.drmFormat = DRM_FORMAT_XBGR8888,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_BYTE,
.withAlpha = false,
},
{
.drmFormat = DRM_FORMAT_ABGR8888,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_BYTE,
.withAlpha = true,
},
{
.drmFormat = DRM_FORMAT_BGR888,
.glFormat = GL_RGB,
.glType = GL_UNSIGNED_BYTE,
.withAlpha = false,
},
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
{
.drmFormat = DRM_FORMAT_RGBX4444,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_SHORT_4_4_4_4,
.withAlpha = false,
},
{
.drmFormat = DRM_FORMAT_RGBA4444,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_SHORT_4_4_4_4,
.withAlpha = true,
},
{
.drmFormat = DRM_FORMAT_RGBX5551,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_SHORT_5_5_5_1,
.withAlpha = false,
},
{
.drmFormat = DRM_FORMAT_RGBA5551,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_SHORT_5_5_5_1,
.withAlpha = true,
},
{
.drmFormat = DRM_FORMAT_RGB565,
.glFormat = GL_RGB,
.glType = GL_UNSIGNED_SHORT_5_6_5,
.withAlpha = false,
},
{
.drmFormat = DRM_FORMAT_XBGR2101010,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT,
.withAlpha = false,
},
{
.drmFormat = DRM_FORMAT_ABGR2101010,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT,
.withAlpha = true,
},
{
.drmFormat = DRM_FORMAT_XBGR16161616F,
.glFormat = GL_RGBA,
.glType = GL_HALF_FLOAT_OES,
.withAlpha = false,
},
{
.drmFormat = DRM_FORMAT_ABGR16161616F,
.glFormat = GL_RGBA,
.glType = GL_HALF_FLOAT_OES,
.withAlpha = true,
},
{
.drmFormat = DRM_FORMAT_XBGR16161616,
.glInternalFormat = GL_RGBA16_EXT,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_SHORT,
.withAlpha = false,
},
{
.drmFormat = DRM_FORMAT_ABGR16161616,
.glInternalFormat = GL_RGBA16_EXT,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_SHORT,
.withAlpha = true,
},
#endif
};
uint32_t CHyprOpenGLImpl::getPreferredReadFormat(CMonitor* pMonitor) {
GLint glf = -1, glt = -1, as = 0;
/*glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &glf);
@ -2453,14 +2521,12 @@ uint32_t CHyprOpenGLImpl::getPreferredReadFormat(CMonitor* pMonitor) {
glGetIntegerv(GL_ALPHA_BITS, &as);*/
if (glf == 0 || glt == 0) {
glf = drmFormatToGL(pMonitor->drmFormat);
glt = glFormatToType(glf);
glf = FormatUtils::drmFormatToGL(pMonitor->drmFormat);
glt = FormatUtils::glFormatToType(glf);
}
for (auto& fmt : GLES2_FORMATS) {
if (fmt.glFormat == glf && fmt.glType == glt && fmt.withAlpha == (as > 0))
return fmt.drmFormat;
}
if (const auto FMT = FormatUtils::getPixelFormatFromGL(glf, glt, as > 0); FMT)
return FMT->drmFormat;
if (m_sExts.EXT_read_format_bgra)
return DRM_FORMAT_XRGB8888;
@ -2468,13 +2534,8 @@ uint32_t CHyprOpenGLImpl::getPreferredReadFormat(CMonitor* pMonitor) {
return DRM_FORMAT_XBGR8888;
}
const SGLPixelFormat* CHyprOpenGLImpl::getPixelFormatFromDRM(uint32_t drmFormat) {
for (auto& fmt : GLES2_FORMATS) {
if (fmt.drmFormat == drmFormat)
return &fmt;
}
return nullptr;
std::vector<SDRMFormat> CHyprOpenGLImpl::getDRMFormats() {
return drmFormats;
}
void SRenderModifData::applyToBox(CBox& box) {

View file

@ -5,6 +5,7 @@
#include "../helpers/Color.hpp"
#include "../helpers/Timer.hpp"
#include "../helpers/Region.hpp"
#include "../helpers/Format.hpp"
#include <list>
#include <unordered_map>
#include <map>
@ -54,14 +55,6 @@ struct SRenderModifData {
bool enabled = true;
};
struct SGLPixelFormat {
uint32_t drmFormat = DRM_FORMAT_INVALID;
GLint glInternalFormat = 0;
GLint glFormat = 0;
GLint glType = 0;
bool withAlpha = false;
};
struct SMonitorRenderData {
CFramebuffer offloadFB;
CFramebuffer mirrorFB; // these are used for some effects,
@ -70,7 +63,7 @@ struct SMonitorRenderData {
CFramebuffer monitorMirrorFB; // used for mirroring outputs, does not contain artifacts like offloadFB
CTexture stencilTex;
SP<CTexture> stencilTex = makeShared<CTexture>();
CFramebuffer blurFB;
bool blurFBDirty = true;
@ -132,74 +125,73 @@ class CHyprOpenGLImpl {
public:
CHyprOpenGLImpl();
void begin(CMonitor*, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional<CRegion> finalDamage = {});
void beginSimple(CMonitor*, const CRegion& damage, CRenderbuffer* rb = nullptr, CFramebuffer* fb = nullptr);
void end();
void begin(CMonitor*, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional<CRegion> finalDamage = {});
void beginSimple(CMonitor*, const CRegion& damage, CRenderbuffer* rb = nullptr, CFramebuffer* fb = nullptr);
void end();
void renderRect(CBox*, const CColor&, int round = 0);
void renderRectWithBlur(CBox*, const CColor&, int round = 0, float blurA = 1.f, bool xray = false);
void renderRectWithDamage(CBox*, const CColor&, CRegion* damage, int round = 0);
void renderTexture(wlr_texture*, CBox*, float a, int round = 0, bool allowCustomUV = false);
void renderTextureWithDamage(wlr_texture*, CBox*, CRegion* damage, float a, int round = 0, bool allowCustomUV = false);
void renderTexture(const CTexture&, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false);
void renderTextureWithDamage(const CTexture&, CBox*, CRegion* damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false);
void renderTextureWithBlur(const CTexture&, CBox*, float a, wlr_surface* pSurface, int round = 0, bool blockBlurOptimization = false, float blurA = 1.f);
void renderRoundedShadow(CBox*, int round, int range, const CColor& color, float a = 1.0);
void renderBorder(CBox*, const CGradientValueData&, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */);
void renderTextureMatte(const CTexture& tex, CBox* pBox, CFramebuffer& matte);
void renderRect(CBox*, const CColor&, int round = 0);
void renderRectWithBlur(CBox*, const CColor&, int round = 0, float blurA = 1.f, bool xray = false);
void renderRectWithDamage(CBox*, const CColor&, CRegion* damage, int round = 0);
void renderTexture(SP<CTexture>, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false);
void renderTextureWithDamage(SP<CTexture>, CBox*, CRegion* damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false);
void renderTextureWithBlur(SP<CTexture>, CBox*, float a, SP<CWLSurfaceResource> pSurface, int round = 0, bool blockBlurOptimization = false, float blurA = 1.f);
void renderRoundedShadow(CBox*, int round, int range, const CColor& color, float a = 1.0);
void renderBorder(CBox*, const CGradientValueData&, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */);
void renderTextureMatte(SP<CTexture> tex, CBox* pBox, CFramebuffer& matte);
void setMonitorTransformEnabled(bool enabled);
void setRenderModifEnabled(bool enabled);
void setMonitorTransformEnabled(bool enabled);
void setRenderModifEnabled(bool enabled);
void saveMatrix();
void setMatrixScaleTranslate(const Vector2D& translate, const float& scale);
void restoreMatrix();
void saveMatrix();
void setMatrixScaleTranslate(const Vector2D& translate, const float& scale);
void restoreMatrix();
void blend(bool enabled);
void blend(bool enabled);
void makeWindowSnapshot(PHLWINDOW);
void makeRawWindowSnapshot(PHLWINDOW, CFramebuffer*);
void makeLayerSnapshot(PHLLS);
void renderSnapshot(PHLWINDOW);
void renderSnapshot(PHLLS);
bool shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow);
void makeWindowSnapshot(PHLWINDOW);
void makeRawWindowSnapshot(PHLWINDOW, CFramebuffer*);
void makeLayerSnapshot(PHLLS);
void renderSnapshot(PHLWINDOW);
void renderSnapshot(PHLLS);
bool shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow);
void clear(const CColor&);
void clearWithTex();
void scissor(const CBox*, bool transform = true);
void scissor(const pixman_box32*, bool transform = true);
void scissor(const int x, const int y, const int w, const int h, bool transform = true);
void clear(const CColor&);
void clearWithTex();
void scissor(const CBox*, bool transform = true);
void scissor(const pixman_box32*, bool transform = true);
void scissor(const int x, const int y, const int w, const int h, bool transform = true);
void destroyMonitorResources(CMonitor*);
void destroyMonitorResources(CMonitor*);
void markBlurDirtyForMonitor(CMonitor*);
void markBlurDirtyForMonitor(CMonitor*);
void preWindowPass();
bool preBlurQueued();
void preRender(CMonitor*);
void preWindowPass();
bool preBlurQueued();
void preRender(CMonitor*);
void saveBufferForMirror(CBox*);
void renderMirrored();
void saveBufferForMirror(CBox*);
void renderMirrored();
void applyScreenShader(const std::string& path);
void applyScreenShader(const std::string& path);
void bindOffMain();
void renderOffToMain(CFramebuffer* off);
void bindBackOnMain();
void bindOffMain();
void renderOffToMain(CFramebuffer* off);
void bindBackOnMain();
void setDamage(const CRegion& damage, std::optional<CRegion> finalDamage = {});
void setDamage(const CRegion& damage, std::optional<CRegion> finalDamage = {});
uint32_t getPreferredReadFormat(CMonitor* pMonitor);
const SGLPixelFormat* getPixelFormatFromDRM(uint32_t drmFormat);
uint32_t getPreferredReadFormat(CMonitor* pMonitor);
std::vector<SDRMFormat> getDRMFormats();
EGLImageKHR createEGLImage(const SDMABUFAttrs& attrs);
SCurrentRenderData m_RenderData;
SCurrentRenderData m_RenderData;
GLint m_iCurrentOutputFb = 0;
GLint m_iCurrentOutputFb = 0;
bool m_bReloadScreenShader = true; // at launch it can be set
bool m_bReloadScreenShader = true; // at launch it can be set
PHLWINDOWREF m_pCurrentWindow; // hack to get the current rendered window
PHLLS m_pCurrentLayer; // hack to get the current rendered layer
PHLWINDOWREF m_pCurrentWindow; // hack to get the current rendered window
PHLLS m_pCurrentLayer; // hack to get the current rendered layer
std::map<PHLWINDOWREF, CFramebuffer> m_mWindowFramebuffers;
std::map<PHLLSREF, CFramebuffer> m_mLayerFramebuffers;
@ -208,41 +200,52 @@ class CHyprOpenGLImpl {
struct {
PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES = nullptr;
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = nullptr;
PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = nullptr;
PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = nullptr;
PFNEGLQUERYDMABUFFORMATSEXTPROC eglQueryDmaBufFormatsEXT = nullptr;
PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT = nullptr;
} m_sProc;
struct {
bool EXT_read_format_bgra = false;
bool EXT_read_format_bgra = false;
bool EXT_image_dma_buf_import = false;
bool EXT_image_dma_buf_import_modifiers = false;
} m_sExts;
private:
std::list<GLuint> m_lBuffers;
std::list<GLuint> m_lTextures;
std::list<GLuint> m_lBuffers;
std::list<GLuint> m_lTextures;
int m_iDRMFD;
std::string m_szExtensions;
std::vector<SDRMFormat> drmFormats;
bool m_bHasModifiers = false;
bool m_bFakeFrame = false;
bool m_bEndFrame = false;
bool m_bApplyFinalShader = false;
bool m_bBlend = false;
bool m_bOffloadedFramebuffer = false;
int m_iDRMFD;
std::string m_szExtensions;
CShader m_sFinalScreenShader;
CTimer m_tGlobalTimer;
bool m_bFakeFrame = false;
bool m_bEndFrame = false;
bool m_bApplyFinalShader = false;
bool m_bBlend = false;
bool m_bOffloadedFramebuffer = false;
void logShaderError(const GLuint&, bool program = false);
GLuint createProgram(const std::string&, const std::string&, bool dynamic = false);
GLuint compileShader(const GLuint&, std::string, bool dynamic = false);
void createBGTextureForMonitor(CMonitor*);
void initShaders();
CShader m_sFinalScreenShader;
CTimer m_tGlobalTimer;
void logShaderError(const GLuint&, bool program = false);
GLuint createProgram(const std::string&, const std::string&, bool dynamic = false);
GLuint compileShader(const GLuint&, std::string, bool dynamic = false);
void createBGTextureForMonitor(CMonitor*);
void initShaders();
void initDRMFormats();
std::vector<uint64_t> getModsForFormat(EGLint format);
// returns the out FB, can be either Mirror or MirrorSwap
CFramebuffer* blurMainFramebufferWithDamage(float a, CRegion* damage);
void renderTextureInternalWithDamage(const CTexture&, CBox* pBox, float a, CRegion* damage, int round = 0, bool discardOpaque = false, bool noAA = false,
void renderTextureInternalWithDamage(SP<CTexture>, CBox* pBox, float a, CRegion* damage, int round = 0, bool discardOpaque = false, bool noAA = false,
bool allowCustomUV = false, bool allowDim = false);
void renderTexturePrimitive(const CTexture& tex, CBox* pBox);
void renderTexturePrimitive(SP<CTexture> tex, CBox* pBox);
void renderSplash(cairo_t* const, cairo_surface_t* const, double offset, const Vector2D& size);
void preBlurForCurrentMonitor();

View file

@ -1,6 +1,7 @@
#include "Renderbuffer.hpp"
#include "OpenGL.hpp"
#include "../Compositor.hpp"
#include "../protocols/types/Buffer.hpp"
#include <dlfcn.h>
@ -61,6 +62,29 @@ CRenderbuffer::CRenderbuffer(wlr_buffer* buffer, uint32_t format) : m_pWlrBuffer
&buffer->events.destroy, [this](void* owner, void* data) { g_pHyprRenderer->onRenderbufferDestroy(this); }, this, "CRenderbuffer");
}
CRenderbuffer::CRenderbuffer(SP<IWLBuffer> buffer, uint32_t format) : m_pHLBuffer(buffer), m_uDrmFormat(format) {
auto dma = buffer->dmabuf();
m_iImage = g_pHyprOpenGL->createEGLImage(dma);
if (m_iImage == EGL_NO_IMAGE_KHR)
throw std::runtime_error("createEGLImage failed");
glGenRenderbuffers(1, &m_iRBO);
glBindRenderbuffer(GL_RENDERBUFFER, m_iRBO);
g_pHyprOpenGL->m_sProc.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, (GLeglImageOES)m_iImage);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glGenFramebuffers(1, &m_sFramebuffer.m_iFb);
m_sFramebuffer.m_vSize = buffer->size;
m_sFramebuffer.bind();
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_iRBO);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
throw std::runtime_error("rbo: glCheckFramebufferStatus failed");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void CRenderbuffer::bind() {
glBindRenderbuffer(GL_RENDERBUFFER, m_iRBO);
bindFB();

View file

@ -3,10 +3,12 @@
#include "Framebuffer.hpp"
class CMonitor;
class IWLBuffer;
class CRenderbuffer {
public:
CRenderbuffer(wlr_buffer* buffer, uint32_t format);
CRenderbuffer(SP<IWLBuffer> buffer, uint32_t format);
~CRenderbuffer();
void bind();
@ -16,6 +18,7 @@ class CRenderbuffer {
uint32_t getFormat();
wlr_buffer* m_pWlrBuffer = nullptr;
WP<IWLBuffer> m_pHLBuffer = {};
DYNLISTENER(destroyBuffer);

View file

@ -1,6 +1,5 @@
#include "Renderer.hpp"
#include "../Compositor.hpp"
#include "linux-dmabuf-unstable-v1-protocol.h"
#include "../helpers/Region.hpp"
#include <algorithm>
#include "../config/ConfigValue.hpp"
@ -13,6 +12,7 @@
#include "../protocols/XDGShell.hpp"
#include "../protocols/PresentationTime.hpp"
#include "../protocols/core/DataDevice.hpp"
#include "../protocols/core/Compositor.hpp"
extern "C" {
#include <xf86drm.h>
@ -90,19 +90,24 @@ CHyprRenderer::CHyprRenderer() {
wl_event_source_timer_update(m_pCursorTicker, 500);
}
static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
const auto TEXTURE = wlr_surface_get_texture(surface);
const auto RDATA = (SRenderData*)data;
const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow.lock() == RDATA->pWindow && g_pInputManager->dragMode == MBIND_RESIZE;
static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* data) {
if (!surface->current.buffer || !surface->current.buffer->texture)
return;
if (!TEXTURE)
const auto& TEXTURE = surface->current.buffer->texture;
const auto RDATA = (SRenderData*)data;
const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow.lock() == RDATA->pWindow && g_pInputManager->dragMode == MBIND_RESIZE;
// this is bad, probably has been logged elsewhere. Means the texture failed
// uploading to the GPU.
if (!TEXTURE->m_iTexID)
return;
TRACY_GPU_ZONE("RenderSurface");
double outputX = -RDATA->pMonitor->vecPosition.x, outputY = -RDATA->pMonitor->vecPosition.y;
auto* const PSURFACE = CWLSurface::surfaceFromWlr(surface);
auto PSURFACE = CWLSurface::fromResource(surface);
const float ALPHA = RDATA->alpha * RDATA->fadeAlpha * (PSURFACE ? PSURFACE->m_pAlphaModifier : 1.F);
@ -140,7 +145,7 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data)
}
} else { // here we clamp to 2, these might be some tiny specks
windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, std::max(surface->current.width, 2), std::max(surface->current.height, 2)};
windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, std::max((float)surface->current.size.x, 2.F), std::max((float)surface->current.size.y, 2.F)};
if (RDATA->pWindow && RDATA->pWindow->m_vRealSize.isBeingAnimated() && RDATA->surface && RDATA->surface != surface && RDATA->squishOversized /* subsurface */) {
// adjust subsurfaces to the window
windowBox.width = (windowBox.width / RDATA->pWindow->m_vReportedSize.x) * RDATA->pWindow->m_vRealSize.value().x;
@ -155,15 +160,23 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data)
windowBox.height = RDATA->h - y;
}
if (windowBox.width <= 1 || windowBox.height <= 1)
if (windowBox.width <= 1 || windowBox.height <= 1) {
if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) {
surface->frame(RDATA->when);
auto FEEDBACK = makeShared<CQueuedPresentationData>(surface);
FEEDBACK->attachMonitor(RDATA->pMonitor);
FEEDBACK->discarded();
PROTO::presentation->queueData(FEEDBACK);
}
return; // invisible
}
windowBox.scale(RDATA->pMonitor->scale);
windowBox.round();
const bool MISALIGNEDFSV1 = std::floor(RDATA->pMonitor->scale) != RDATA->pMonitor->scale /* Fractional */ && surface->current.scale == 1 /* fs protocol */ &&
windowBox.size() != Vector2D{surface->current.buffer_width, surface->current.buffer_height} /* misaligned */ &&
DELTALESSTHAN(windowBox.width, surface->current.buffer_width, 3) && DELTALESSTHAN(windowBox.height, surface->current.buffer_height, 3) /* off by one-or-two */ &&
windowBox.size() != surface->current.buffer->size /* misaligned */ && DELTALESSTHAN(windowBox.width, surface->current.buffer->size.x, 3) &&
DELTALESSTHAN(windowBox.height, surface->current.buffer->size.y, 3) /* off by one-or-two */ &&
(!RDATA->pWindow || (!RDATA->pWindow->m_vRealSize.isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */;
g_pHyprRenderer->calculateUVForSurface(RDATA->pWindow, surface, RDATA->surface == surface, windowBox.size(), MISALIGNEDFSV1);
@ -183,8 +196,8 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data)
if (RDATA->dontRound)
rounding = 0;
const bool WINDOWOPAQUE = RDATA->pWindow && RDATA->pWindow->m_pWLSurface.wlr() == surface ? RDATA->pWindow->opaque() : false;
const bool CANDISABLEBLEND = ALPHA >= 1.f && rounding == 0 && (WINDOWOPAQUE || surface->opaque);
const bool WINDOWOPAQUE = RDATA->pWindow && RDATA->pWindow->m_pWLSurface->resource() == surface ? RDATA->pWindow->opaque() : false;
const bool CANDISABLEBLEND = ALPHA >= 1.f && rounding == 0 && WINDOWOPAQUE;
if (CANDISABLEBLEND)
g_pHyprOpenGL->blend(false);
@ -195,16 +208,16 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data)
if (RDATA->blur)
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, surface, rounding, RDATA->blockBlurOptimization, RDATA->fadeAlpha);
else
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding, true);
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding);
} else {
if (RDATA->blur && RDATA->popup)
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, surface, rounding, true, RDATA->fadeAlpha);
else
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding, true);
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding);
}
if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) {
wlr_surface_send_frame_done(surface, RDATA->when);
surface->frame(RDATA->when);
auto FEEDBACK = makeShared<CQueuedPresentationData>(surface);
FEEDBACK->attachMonitor(RDATA->pMonitor);
FEEDBACK->presented();
@ -506,7 +519,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec
if (ignoreAllGeometry)
decorate = false;
renderdata.surface = pWindow->m_pWLSurface.wlr();
renderdata.surface = pWindow->m_pWLSurface->resource();
renderdata.dontRound = (pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) || (!pWindow->m_sSpecialRenderData.rounding);
renderdata.fadeAlpha = pWindow->m_fAlpha.value() * (pWindow->m_bPinned ? 1.f : PWORKSPACE->m_fAlpha.value());
renderdata.alpha = pWindow->m_fActiveInactiveAlpha.value();
@ -576,7 +589,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec
if ((pWindow->m_bIsX11 && *PXWLUSENN) || pWindow->m_sAdditionalConfigData.nearestNeighbor.toUnderlying())
g_pHyprOpenGL->m_RenderData.useNearestNeighbor = true;
if (!pWindow->m_sAdditionalConfigData.forceNoBlur && pWindow->m_pWLSurface.small() && !pWindow->m_pWLSurface.m_bFillIgnoreSmall && renderdata.blur && *PBLUR) {
if (!pWindow->m_sAdditionalConfigData.forceNoBlur && pWindow->m_pWLSurface->small() && !pWindow->m_pWLSurface->m_bFillIgnoreSmall && renderdata.blur && *PBLUR) {
CBox wb = {renderdata.x - pMonitor->vecPosition.x, renderdata.y - pMonitor->vecPosition.y, renderdata.w, renderdata.h};
wb.scale(pMonitor->scale).round();
g_pHyprOpenGL->renderRectWithBlur(&wb, CColor(0, 0, 0, 0), renderdata.dontRound ? 0 : renderdata.rounding - 1, renderdata.fadeAlpha,
@ -584,7 +597,8 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec
renderdata.blur = false;
}
wlr_surface_for_each_surface(pWindow->m_pWLSurface.wlr(), renderSurface, &renderdata);
pWindow->m_pWLSurface->resource()->breadthfirst([](SP<CWLSurfaceResource> s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); },
&renderdata);
g_pHyprOpenGL->m_RenderData.useNearestNeighbor = false;
@ -641,14 +655,15 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec
pWindow->m_pPopupHead->breadthfirst(
[](CPopup* popup, void* data) {
if (!popup->m_sWLSurface.wlr())
if (!popup->m_pWLSurface || !popup->m_pWLSurface->resource())
return;
auto pos = popup->coordsRelativeToParent();
auto rd = (SRenderData*)data;
Vector2D oldPos = {rd->x, rd->y};
rd->x += pos.x;
rd->y += pos.y;
wlr_surface_for_each_surface(popup->m_sWLSurface.wlr(), renderSurface, rd);
popup->m_pWLSurface->resource()->breadthfirst([](SP<CWLSurfaceResource> s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); },
data);
rd->x = oldPos.x;
rd->y = oldPos.y;
},
@ -698,7 +713,7 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, CMonitor* pMonitor, timespec* time
SRenderData renderdata = {pMonitor, time, REALPOS.x, REALPOS.y};
renderdata.fadeAlpha = pLayer->alpha.value();
renderdata.blur = pLayer->forceBlur;
renderdata.surface = pLayer->layerSurface->surface;
renderdata.surface = pLayer->surface->resource();
renderdata.decorate = false;
renderdata.w = REALSIZ.x;
renderdata.h = REALSIZ.y;
@ -717,7 +732,7 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, CMonitor* pMonitor, timespec* time
}
if (!popups)
wlr_surface_for_each_surface(pLayer->layerSurface->surface, renderSurface, &renderdata);
pLayer->surface->resource()->breadthfirst([](SP<CWLSurfaceResource> s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); }, &renderdata);
renderdata.squishOversized = false; // don't squish popups
renderdata.dontRound = true;
@ -726,11 +741,11 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, CMonitor* pMonitor, timespec* time
if (popups) {
pLayer->popupHead->breadthfirst(
[](CPopup* popup, void* data) {
if (!popup->m_sWLSurface.wlr())
if (!popup->m_pWLSurface || !popup->m_pWLSurface->resource())
return;
Vector2D pos = popup->coordsRelativeToParent();
renderSurface(popup->m_sWLSurface.wlr(), pos.x, pos.y, data);
renderSurface(popup->m_pWLSurface->resource(), pos.x, pos.y, data);
},
&renderdata);
}
@ -746,15 +761,15 @@ void CHyprRenderer::renderIMEPopup(CInputPopup* pPopup, CMonitor* pMonitor, time
SRenderData renderdata = {pMonitor, time, POS.x, POS.y};
const auto SURF = pPopup->getWlrSurface();
const auto SURF = pPopup->getSurface();
renderdata.blur = false;
renderdata.surface = SURF;
renderdata.decorate = false;
renderdata.w = SURF->current.width;
renderdata.h = SURF->current.height;
renderdata.w = SURF->current.size.x;
renderdata.h = SURF->current.size.y;
wlr_surface_for_each_surface(SURF, renderSurface, &renderdata);
SURF->breadthfirst([](SP<CWLSurfaceResource> s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); }, &renderdata);
}
void CHyprRenderer::renderSessionLockSurface(SSessionLockSurface* pSurface, CMonitor* pMonitor, timespec* time) {
@ -766,7 +781,7 @@ void CHyprRenderer::renderSessionLockSurface(SSessionLockSurface* pSurface, CMon
renderdata.w = pMonitor->vecSize.x;
renderdata.h = pMonitor->vecSize.y;
wlr_surface_for_each_surface(pSurface->surface->surface(), renderSurface, &renderdata);
renderdata.surface->breadthfirst([](SP<CWLSurfaceResource> s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); }, &renderdata);
}
void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* time, const Vector2D& translate, const float& scale) {
@ -966,17 +981,15 @@ void CHyprRenderer::renderLockscreen(CMonitor* pMonitor, timespec* now, const CB
}
}
void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, wlr_surface* pSurface, bool main, const Vector2D& projSize, bool fixMisalignedFSV1) {
void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface, bool main, const Vector2D& projSize, bool fixMisalignedFSV1) {
if (!pWindow || !pWindow->m_bIsX11) {
Vector2D uvTL;
Vector2D uvBR = Vector2D(1, 1);
if (pSurface->current.viewport.has_src) {
if (pSurface->current.viewport.hasSource) {
// we stretch it to dest. if no dest, to 1,1
wlr_fbox bufferSource;
wlr_surface_get_buffer_source_box(pSurface, &bufferSource);
Vector2D bufferSize = Vector2D(pSurface->buffer->texture->width, pSurface->buffer->texture->height);
Vector2D bufferSize = pSurface->current.buffer->size;
auto bufferSource = pSurface->current.viewport.source;
// calculate UV for the basic src_box. Assume dest == size. Scale to dest later
uvTL = Vector2D(bufferSource.x / bufferSize.x, bufferSource.y / bufferSize.y);
@ -991,8 +1004,8 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, wlr_surface* pSurfa
if (projSize != Vector2D{} && fixMisalignedFSV1) {
// instead of nearest_neighbor (we will repeat / skip)
// just cut off / expand surface
const Vector2D PIXELASUV = Vector2D{1, 1} / Vector2D{pSurface->buffer->texture->width, pSurface->buffer->texture->height};
const Vector2D MISALIGNMENT = Vector2D{pSurface->buffer->texture->width, pSurface->buffer->texture->height} - projSize;
const Vector2D PIXELASUV = Vector2D{1, 1} / pSurface->current.buffer->size;
const Vector2D MISALIGNMENT = pSurface->current.buffer->size - projSize;
if (MISALIGNMENT != Vector2D{})
uvBR -= MISALIGNMENT * PIXELASUV;
}
@ -1013,10 +1026,10 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, wlr_surface* pSurfa
// ignore X and Y, adjust uv
if (geom.x != 0 || geom.y != 0 || geom.width > pWindow->m_vRealSize.value().x || geom.height > pWindow->m_vRealSize.value().y) {
const auto XPERC = (double)geom.x / (double)pSurface->current.width;
const auto YPERC = (double)geom.y / (double)pSurface->current.height;
const auto WPERC = (double)(geom.x + geom.width) / (double)pSurface->current.width;
const auto HPERC = (double)(geom.y + geom.height) / (double)pSurface->current.height;
const auto XPERC = (double)geom.x / (double)pSurface->current.size.x;
const auto YPERC = (double)geom.y / (double)pSurface->current.size.y;
const auto WPERC = (double)(geom.x + geom.width) / (double)pSurface->current.size.x;
const auto HPERC = (double)(geom.y + geom.height) / (double)pSurface->current.size.y;
const auto TOADDTL = Vector2D(XPERC * (uvBR.x - uvTL.x), YPERC * (uvBR.y - uvTL.y));
uvBR = uvBR - Vector2D(1.0 - WPERC * (uvBR.x - uvTL.x), 1.0 - HPERC * (uvBR.y - uvTL.y));
@ -1025,8 +1038,8 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, wlr_surface* pSurfa
// TODO: make this passed to the func. Might break in the future.
auto maxSize = pWindow->m_vRealSize.value();
if (pWindow->m_pWLSurface.small() && !pWindow->m_pWLSurface.m_bFillIgnoreSmall)
maxSize = pWindow->m_pWLSurface.getViewporterCorrectedSize();
if (pWindow->m_pWLSurface->small() && !pWindow->m_pWLSurface->m_bFillIgnoreSmall)
maxSize = pWindow->m_pWLSurface->getViewporterCorrectedSize();
if (geom.width > maxSize.x)
uvBR.x = uvBR.x * (maxSize.x / geom.width);
@ -1048,53 +1061,51 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, wlr_surface* pSurfa
}
}
void countSubsurfacesIter(wlr_surface* pSurface, int x, int y, void* data) {
*(int*)data += 1;
}
bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) {
if (!pMonitor->mirrors.empty() || pMonitor->isMirror() || m_bDirectScanoutBlocked)
return false; // do not DS if this monitor is being mirrored. Will break the functionality.
return false; // FIXME: fix when we move to new lib for backend.
if (!wlr_output_is_direct_scanout_allowed(pMonitor->output))
return false;
// if (!pMonitor->mirrors.empty() || pMonitor->isMirror() || m_bDirectScanoutBlocked)
// return false; // do not DS if this monitor is being mirrored. Will break the functionality.
const auto PCANDIDATE = pMonitor->solitaryClient.lock();
// if (!wlr_output_is_direct_scanout_allowed(pMonitor->output))
// return false;
if (!PCANDIDATE)
return false;
// const auto PCANDIDATE = pMonitor->solitaryClient.lock();
const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE);
// if (!PCANDIDATE)
// return false;
if (!PSURFACE || PSURFACE->current.scale != pMonitor->output->scale || PSURFACE->current.transform != pMonitor->output->transform)
return false;
// const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE);
// finally, we should be GTG.
wlr_output_state_set_buffer(pMonitor->state.wlr(), &PSURFACE->buffer->base);
// if (!PSURFACE || PSURFACE->current.scale != pMonitor->output->scale || PSURFACE->current.transform != pMonitor->output->transform)
// return false;
if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr()))
return false;
// // finally, we should be GTG.
// wlr_output_state_set_buffer(pMonitor->state.wlr(), &PSURFACE->buffer->base);
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
wlr_surface_send_frame_done(PSURFACE, &now);
auto FEEDBACK = makeShared<CQueuedPresentationData>(PSURFACE);
FEEDBACK->attachMonitor(pMonitor);
FEEDBACK->presented();
FEEDBACK->setPresentationType(true);
PROTO::presentation->queueData(FEEDBACK);
// if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr()))
// return false;
if (pMonitor->state.commit()) {
if (m_pLastScanout.expired()) {
m_pLastScanout = PCANDIDATE;
Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle);
}
} else {
m_pLastScanout.reset();
return false;
}
// timespec now;
// clock_gettime(CLOCK_MONOTONIC, &now);
// PSURFACE->frame(&now);
// auto FEEDBACK = makeShared<CQueuedPresentationData>(PSURFACE);
// FEEDBACK->attachMonitor(pMonitor);
// FEEDBACK->presented();
// FEEDBACK->setPresentationType(true);
// PROTO::presentation->queueData(FEEDBACK);
return true;
// if (pMonitor->state.commit()) {
// if (m_pLastScanout.expired()) {
// m_pLastScanout = PCANDIDATE;
// Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle);
// }
// } else {
// m_pLastScanout.reset();
// return false;
// }
// return true;
}
void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
@ -1430,53 +1441,52 @@ void CHyprRenderer::renderWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace,
void CHyprRenderer::sendFrameEventsToWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now) {
for (auto& w : g_pCompositor->m_vWindows) {
if (w->isHidden() || !w->m_bIsMapped || w->m_bFadingOut || !w->m_pWLSurface.wlr())
if (w->isHidden() || !w->m_bIsMapped || w->m_bFadingOut || !w->m_pWLSurface->resource())
continue;
if (!shouldRenderWindow(w, pMonitor))
continue;
wlr_surface_for_each_surface(
w->m_pWLSurface.wlr(), [](wlr_surface* s, int x, int y, void* data) { wlr_surface_send_frame_done(s, (timespec*)data); }, now);
w->m_pWLSurface->resource()->breadthfirst([now](SP<CWLSurfaceResource> r, const Vector2D& offset, void* d) { r->frame(now); }, nullptr);
}
for (auto& lsl : pMonitor->m_aLayerSurfaceLayers) {
for (auto& ls : lsl) {
if (ls->fadingOut || !ls->surface.wlr())
if (ls->fadingOut || !ls->surface->resource())
continue;
wlr_surface_for_each_surface(
ls->surface.wlr(), [](wlr_surface* s, int x, int y, void* data) { wlr_surface_send_frame_done(s, (timespec*)data); }, now);
ls->surface->resource()->breadthfirst([now](SP<CWLSurfaceResource> r, const Vector2D& offset, void* d) { r->frame(now); }, nullptr);
}
}
}
void CHyprRenderer::setWindowScanoutMode(PHLWINDOW pWindow) {
if (!g_pCompositor->m_sWLRLinuxDMABuf || g_pSessionLockManager->isSessionLocked())
return;
// FIXME: fix when moved to new impl
// if (!g_pCompositor->m_sWLRLinuxDMABuf || g_pSessionLockManager->isSessionLocked())
// return;
if (!pWindow->m_bIsFullscreen) {
wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface.wlr(), nullptr);
Debug::log(LOG, "Scanout mode OFF set for {}", pWindow);
return;
}
// if (!pWindow->m_bIsFullscreen) {
// wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface->resource(), nullptr);
// Debug::log(LOG, "Scanout mode OFF set for {}", pWindow);
// return;
// }
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
// const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
const wlr_linux_dmabuf_feedback_v1_init_options INIT_OPTIONS = {
.main_renderer = g_pCompositor->m_sWLRRenderer,
.scanout_primary_output = PMONITOR->output,
};
// const wlr_linux_dmabuf_feedback_v1_init_options INIT_OPTIONS = {
// .main_renderer = g_pCompositor->m_sWLRRenderer,
// .scanout_primary_output = PMONITOR->output,
// };
wlr_linux_dmabuf_feedback_v1 feedback = {0};
// wlr_linux_dmabuf_feedback_v1 feedback = {0};
if (!wlr_linux_dmabuf_feedback_v1_init_with_options(&feedback, &INIT_OPTIONS))
return;
// if (!wlr_linux_dmabuf_feedback_v1_init_with_options(&feedback, &INIT_OPTIONS))
// return;
wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface.wlr(), &feedback);
wlr_linux_dmabuf_feedback_v1_finish(&feedback);
// wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface->resource(), &feedback);
// wlr_linux_dmabuf_feedback_v1_finish(&feedback);
Debug::log(LOG, "Scanout mode ON set for {}", pWindow);
// Debug::log(LOG, "Scanout mode ON set for {}", pWindow);
}
// taken from Sway.
@ -1662,26 +1672,25 @@ void CHyprRenderer::arrangeLayersForMonitor(const int& monitor) {
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitor);
}
void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y, double scale) {
void CHyprRenderer::damageSurface(SP<CWLSurfaceResource> pSurface, double x, double y, double scale) {
if (!pSurface)
return; // wut?
if (g_pCompositor->m_bUnsafeState)
return;
const auto WLSURF = CWLSurface::surfaceFromWlr(pSurface);
const auto WLSURF = CWLSurface::fromResource(pSurface);
CRegion damageBox = WLSURF ? WLSURF->logicalDamage() : CRegion{};
if (!WLSURF) {
Debug::log(ERR, "BUG THIS: No CWLSurface for surface in damageSurface!!!");
wlr_surface_get_effective_damage(pSurface, damageBox.pixman());
return;
}
if (scale != 1.0)
damageBox.scale(scale);
// schedule frame events
if (!wl_list_empty(&pSurface->current.frame_callback_list))
g_pCompositor->scheduleFrameForMonitor(g_pCompositor->getMonitorFromVector(Vector2D(x, y)));
g_pCompositor->scheduleFrameForMonitor(g_pCompositor->getMonitorFromVector(Vector2D(x, y)));
if (damageBox.empty())
return;
@ -1836,7 +1845,6 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
pMonitor->onDisconnect();
pMonitor->events.modeChanged.emit();
pMonitor->updateGlobal();
return true;
}
@ -2242,12 +2250,11 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
EMIT_HOOK_EVENT("monitorLayoutChanged", nullptr);
pMonitor->events.modeChanged.emit();
pMonitor->updateGlobal();
return true;
}
void CHyprRenderer::setCursorSurface(CWLSurface* surf, int hotspotX, int hotspotY, bool force) {
void CHyprRenderer::setCursorSurface(SP<CWLSurface> surf, int hotspotX, int hotspotY, bool force) {
m_bCursorHasSurface = surf;
m_sLastCursorData.name = "";
@ -2464,8 +2471,8 @@ bool CHyprRenderer::canSkipBackBufferClear(CMonitor* pMonitor) {
continue;
// TODO: cache maybe?
CRegion opaque = &ls->layerSurface->surface->opaque_region;
CBox lsbox = {0, 0, ls->layerSurface->surface->current.buffer_width, ls->layerSurface->surface->current.buffer_height};
CRegion opaque = ls->layerSurface->surface->current.opaque;
CBox lsbox = {{}, ls->layerSurface->surface->current.size};
opaque.invert(lsbox);
if (!opaque.empty())
@ -2544,6 +2551,15 @@ CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(wlr_buffer* buffer, uint32
return m_vRenderbuffers.emplace_back(std::make_unique<CRenderbuffer>(buffer, fmt)).get();
}
CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(SP<IWLBuffer> buffer, uint32_t fmt) {
auto it = std::find_if(m_vRenderbuffers.begin(), m_vRenderbuffers.end(), [&](const auto& other) { return other->m_pHLBuffer == buffer; });
if (it != m_vRenderbuffers.end())
return it->get();
return m_vRenderbuffers.emplace_back(std::make_unique<CRenderbuffer>(buffer, fmt)).get();
}
void CHyprRenderer::makeEGLCurrent() {
if (!g_pCompositor)
return;
@ -2556,7 +2572,7 @@ void CHyprRenderer::unsetEGL() {
eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, wlr_buffer* buffer, CFramebuffer* fb, bool simple) {
bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, SP<IWLBuffer> buffer, CFramebuffer* fb, bool simple) {
makeEGLCurrent();
@ -2586,10 +2602,13 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode
return false;
}
} else
m_pCurrentWlrBuffer = wlr_buffer_lock(buffer);
m_pCurrentHLBuffer = buffer;
try {
m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentWlrBuffer, pMonitor->drmFormat);
if (m_pCurrentWlrBuffer)
m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentWlrBuffer, pMonitor->drmFormat);
else
m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentHLBuffer.lock(), pMonitor->drmFormat);
} catch (std::exception& e) {
Debug::log(ERR, "getOrCreateRenderbuffer failed for {}", pMonitor->szName);
wlr_buffer_unlock(m_pCurrentWlrBuffer);

View file

@ -12,6 +12,7 @@ struct SMonitorRule;
class CWorkspace;
class CWindow;
class CInputPopup;
class IWLBuffer;
// TODO: add fuller damage tracking for updating only parts of a window
enum DAMAGETRACKINGMODES {
@ -44,7 +45,7 @@ class CHyprRenderer {
void renderMonitor(CMonitor* pMonitor);
void arrangeLayersForMonitor(const int&);
void damageSurface(wlr_surface*, double, double, double scale = 1.0);
void damageSurface(SP<CWLSurfaceResource>, double, double, double scale = 1.0);
void damageWindow(PHLWINDOW, bool forceFull = false);
void damageBox(CBox*);
void damageBox(const int& x, const int& y, const int& w, const int& h);
@ -57,14 +58,14 @@ class CHyprRenderer {
void ensureCursorRenderingMode();
bool shouldRenderCursor();
void setCursorHidden(bool hide);
void calculateUVForSurface(PHLWINDOW, wlr_surface*, bool main = false, const Vector2D& projSize = {}, bool fixMisalignedFSV1 = false);
void calculateUVForSurface(PHLWINDOW, SP<CWLSurfaceResource>, bool main = false, const Vector2D& projSize = {}, bool fixMisalignedFSV1 = false);
std::tuple<float, float, float> getRenderTimes(CMonitor* pMonitor); // avg max min
void renderLockscreen(CMonitor* pMonitor, timespec* now, const CBox& geometry);
void setOccludedForBackLayers(CRegion& region, PHLWORKSPACE pWorkspace);
void setOccludedForMainWorkspace(CRegion& region, PHLWORKSPACE pWorkspace); // TODO: merge occlusion methods
bool canSkipBackBufferClear(CMonitor* pMonitor);
void recheckSolitaryForMonitor(CMonitor* pMonitor);
void setCursorSurface(CWLSurface* surf, int hotspotX, int hotspotY, bool force = false);
void setCursorSurface(SP<CWLSurface> surf, int hotspotX, int hotspotY, bool force = false);
void setCursorFromName(const std::string& name, bool force = false);
void onRenderbufferDestroy(CRenderbuffer* rb);
CRenderbuffer* getCurrentRBO();
@ -74,7 +75,7 @@ class CHyprRenderer {
// if RENDER_MODE_NORMAL, provided damage will be written to.
// otherwise, it will be the one used.
bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, wlr_buffer* buffer = nullptr, CFramebuffer* fb = nullptr, bool simple = false);
bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP<IWLBuffer> buffer = {}, CFramebuffer* fb = nullptr, bool simple = false);
void endRender();
bool m_bBlockSurfaceFeedback = false;
@ -98,10 +99,10 @@ class CHyprRenderer {
CTimer m_tRenderTimer;
struct {
int hotspotX;
int hotspotY;
std::optional<CWLSurface*> surf = nullptr;
std::string name;
int hotspotX;
int hotspotY;
std::optional<SP<CWLSurface>> surf;
std::string name;
} m_sLastCursorData;
private:
@ -121,6 +122,7 @@ class CHyprRenderer {
bool m_bCursorHasSurface = false;
CRenderbuffer* m_pCurrentRenderbuffer = nullptr;
wlr_buffer* m_pCurrentWlrBuffer = nullptr;
WP<IWLBuffer> m_pCurrentHLBuffer = {};
eRenderMode m_eRenderMode = RENDER_MODE_NORMAL;
bool m_bNvidia = false;
@ -132,6 +134,7 @@ class CHyprRenderer {
} m_sCursorHiddenConditions;
CRenderbuffer* getOrCreateRenderbuffer(wlr_buffer* buffer, uint32_t fmt);
CRenderbuffer* getOrCreateRenderbuffer(SP<IWLBuffer> buffer, uint32_t fmt);
std::vector<std::unique_ptr<CRenderbuffer>> m_vRenderbuffers;
friend class CHyprOpenGLImpl;

View file

@ -1,16 +1,54 @@
#include "Texture.hpp"
#include "Renderer.hpp"
#include "../Compositor.hpp"
#include "../protocols/types/Buffer.hpp"
#include "../helpers/Format.hpp"
CTexture::CTexture() {
// naffin'
}
CTexture::~CTexture() {
if (m_bNonOwning)
return;
g_pHyprRenderer->makeEGLCurrent();
destroyTexture();
}
CTexture::CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_) {
g_pHyprRenderer->makeEGLCurrent();
const auto format = FormatUtils::getPixelFormatFromDRM(drmFormat);
ASSERT(format);
m_iType = format->withAlpha ? TEXTURE_RGBA : TEXTURE_RGBX;
m_vSize = size_;
allocate();
GLCALL(glBindTexture(GL_TEXTURE_2D, m_iTexID));
GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
#ifndef GLES2
if (format->flipRB) {
GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE));
GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED));
}
#endif
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));
GLCALL(glBindTexture(GL_TEXTURE_2D, 0));
}
CTexture::CTexture(wlr_texture* tex) {
RASSERT(wlr_texture_is_gles2(tex), "wlr_texture provided to CTexture that isn't GLES2!");
wlr_gles2_texture_attribs attrs;
wlr_gles2_texture_get_attribs(tex, &attrs);
m_iTarget = attrs.target;
m_iTexID = attrs.tex;
m_iTarget = attrs.target;
m_iTexID = attrs.tex;
m_bNonOwning = true;
if (m_iTarget == GL_TEXTURE_2D)
m_iType = attrs.has_alpha ? TEXTURE_RGBA : TEXTURE_RGBX;
@ -20,14 +58,72 @@ CTexture::CTexture(wlr_texture* tex) {
m_vSize = Vector2D(tex->width, tex->height);
}
CTexture::CTexture(const SDMABUFAttrs& attrs, void* image) {
if (!g_pHyprOpenGL->m_sProc.glEGLImageTargetTexture2DOES) {
Debug::log(ERR, "Cannot create a dmabuf texture: no glEGLImageTargetTexture2DOES");
return;
}
m_iTarget = GL_TEXTURE_2D;
m_iType = TEXTURE_RGBA;
m_vSize = attrs.size;
m_iType = FormatUtils::isFormatOpaque(attrs.format) ? TEXTURE_RGBX : TEXTURE_RGBA;
allocate();
m_pEglImage = image;
GLCALL(glBindTexture(GL_TEXTURE_2D, m_iTexID));
GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
GLCALL(g_pHyprOpenGL->m_sProc.glEGLImageTargetTexture2DOES(m_iTarget, image));
GLCALL(glBindTexture(GL_TEXTURE_2D, 0));
}
void CTexture::update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage) {
g_pHyprRenderer->makeEGLCurrent();
const auto format = FormatUtils::getPixelFormatFromDRM(drmFormat);
ASSERT(format);
glBindTexture(GL_TEXTURE_2D, m_iTexID);
auto rects = damage.copy().intersect(CBox{{}, m_vSize}).getRects();
#ifndef GLES2
if (format->flipRB) {
GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE));
GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED));
}
#endif
for (auto& rect : rects) {
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));
glBindTexture(GL_TEXTURE_2D, 0);
}
void CTexture::destroyTexture() {
if (m_iTexID) {
glDeleteTextures(1, &m_iTexID);
GLCALL(glDeleteTextures(1, &m_iTexID));
m_iTexID = 0;
}
if (m_pEglImage)
g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), m_pEglImage);
m_pEglImage = nullptr;
}
void CTexture::allocate() {
if (!m_iTexID)
glGenTextures(1, &m_iTexID);
}
GLCALL(glGenTextures(1, &m_iTexID));
}

View file

@ -2,6 +2,10 @@
#include "../defines.hpp"
class IWLBuffer;
struct SDMABUFAttrs;
class CRegion;
enum TEXTURETYPE {
TEXTURE_INVALID, // Invalid
TEXTURE_RGBA, // 4 channels
@ -12,13 +16,27 @@ enum TEXTURETYPE {
class CTexture {
public:
CTexture();
CTexture(CTexture&) = delete;
CTexture(CTexture&&) = delete;
CTexture(const CTexture&&) = delete;
CTexture(const CTexture&) = delete;
CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size);
CTexture(wlr_texture*);
// this ctor takes ownership of the eglImage.
CTexture(const SDMABUFAttrs&, void* image);
~CTexture();
void destroyTexture();
void allocate();
void update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage);
TEXTURETYPE m_iType = TEXTURE_RGBA;
GLenum m_iTarget = GL_TEXTURE_2D;
GLuint m_iTexID = 0;
Vector2D m_vSize;
void* m_pEglImage = nullptr;
bool m_bNonOwning = false; // wlr
};

View file

@ -6,23 +6,23 @@
#include <pango/pangocairo.h>
// shared things to conserve VRAM
static CTexture m_tGradientActive;
static CTexture m_tGradientInactive;
static CTexture m_tGradientLockedActive;
static CTexture m_tGradientLockedInactive;
static SP<CTexture> m_tGradientActive = makeShared<CTexture>();
static SP<CTexture> m_tGradientInactive = makeShared<CTexture>();
static SP<CTexture> m_tGradientLockedActive = makeShared<CTexture>();
static SP<CTexture> m_tGradientLockedInactive = makeShared<CTexture>();
constexpr int BAR_INDICATOR_HEIGHT = 3;
constexpr int BAR_PADDING_OUTER_VERT = 2;
constexpr int BAR_PADDING_OUTER_HORZ = 2;
constexpr int BAR_TEXT_PAD = 2;
constexpr int BAR_HORIZONTAL_PADDING = 2;
constexpr int BAR_INDICATOR_HEIGHT = 3;
constexpr int BAR_PADDING_OUTER_VERT = 2;
constexpr int BAR_PADDING_OUTER_HORZ = 2;
constexpr int BAR_TEXT_PAD = 2;
constexpr int BAR_HORIZONTAL_PADDING = 2;
CHyprGroupBarDecoration::CHyprGroupBarDecoration(PHLWINDOW pWindow) : IHyprWindowDecoration(pWindow) {
static auto PGRADIENTS = CConfigValue<Hyprlang::INT>("group:groupbar:enabled");
static auto PENABLED = CConfigValue<Hyprlang::INT>("group:groupbar:gradients");
m_pWindow = pWindow;
if (m_tGradientActive.m_iTexID == 0 && *PENABLED && *PGRADIENTS)
if (m_tGradientActive->m_iTexID == 0 && *PENABLED && *PGRADIENTS)
refreshGroupBarGradients();
}
@ -157,10 +157,9 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) {
rect.scale(pMonitor->scale);
if (*PGRADIENTS) {
const auto& GRADIENTTEX =
(m_dwGroupMembers[WINDOWINDEX].lock() == g_pCompositor->m_pLastWindow.lock() ? (GROUPLOCKED ? m_tGradientLockedActive : m_tGradientActive) :
(GROUPLOCKED ? m_tGradientLockedInactive : m_tGradientInactive));
if (GRADIENTTEX.m_iTexID != 0)
const auto GRADIENTTEX = (m_dwGroupMembers[WINDOWINDEX] == g_pCompositor->m_pLastWindow ? (GROUPLOCKED ? m_tGradientLockedActive : m_tGradientActive) :
(GROUPLOCKED ? m_tGradientLockedInactive : m_tGradientInactive));
if (GRADIENTTEX->m_iTexID != 0)
g_pHyprOpenGL->renderTexture(GRADIENTTEX, &rect, 1.0);
}
@ -204,6 +203,7 @@ void CHyprGroupBarDecoration::invalidateTextures() {
}
CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float monitorScale) {
tex = makeShared<CTexture>();
szContent = pWindow->m_szTitle;
pWindowOwner = pWindow;
const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, bufferSize.x, bufferSize.y);
@ -254,8 +254,8 @@ CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float
// copy the data to an OpenGL texture we have
const auto DATA = cairo_image_surface_get_data(CAIROSURFACE);
tex.allocate();
glBindTexture(GL_TEXTURE_2D, tex.m_iTexID);
tex->allocate();
glBindTexture(GL_TEXTURE_2D, tex->m_iTexID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@ -272,10 +272,10 @@ CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float
}
CTitleTex::~CTitleTex() {
tex.destroyTexture();
tex->destroyTexture();
}
void renderGradientTo(CTexture& tex, CGradientValueData* grad) {
void renderGradientTo(SP<CTexture> tex, CGradientValueData* grad) {
if (!g_pCompositor->m_pLastMonitor)
return;
@ -308,8 +308,8 @@ void renderGradientTo(CTexture& tex, CGradientValueData* grad) {
// copy the data to an OpenGL texture we have
const auto DATA = cairo_image_surface_get_data(CAIROSURFACE);
tex.allocate();
glBindTexture(GL_TEXTURE_2D, tex.m_iTexID);
tex->allocate();
glBindTexture(GL_TEXTURE_2D, tex->m_iTexID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@ -340,11 +340,11 @@ void refreshGroupBarGradients() {
g_pHyprRenderer->makeEGLCurrent();
if (m_tGradientActive.m_iTexID != 0) {
m_tGradientActive.destroyTexture();
m_tGradientInactive.destroyTexture();
m_tGradientLockedActive.destroyTexture();
m_tGradientLockedInactive.destroyTexture();
if (m_tGradientActive->m_iTexID != 0) {
m_tGradientActive->destroyTexture();
m_tGradientInactive->destroyTexture();
m_tGradientLockedActive->destroyTexture();
m_tGradientLockedInactive->destroyTexture();
}
if (!*PENABLED || !*PGRADIENTS)

View file

@ -12,7 +12,7 @@ class CTitleTex {
CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float monitorScale);
~CTitleTex();
CTexture tex;
SP<CTexture> tex;
std::string szContent;
PHLWINDOWREF pWindowOwner;
};