mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-11-13 15:27:21 +00:00
[client] egl: add portable texture upload fallback
This commit is contained in:
@@ -1,16 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(renderer_EGL LANGUAGES C CXX)
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(RENDERER_EGL REQUIRED IMPORTED_TARGET
|
||||
egl
|
||||
gl
|
||||
)
|
||||
|
||||
pkg_check_modules(RENDERER_EGL_OPT IMPORTED_TARGET
|
||||
wayland-egl
|
||||
)
|
||||
|
||||
find_program(AWK NAMES gawk mawk original-awk awk)
|
||||
|
||||
if(AWK MATCHES ".+-NOTFOUND")
|
||||
@@ -75,7 +65,7 @@ make_defines(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/shader/desktop_rgb.def.h"
|
||||
)
|
||||
|
||||
add_library(renderer_EGL STATIC
|
||||
set(RENDERER_EGL_SOURCES
|
||||
egl.c
|
||||
egldebug.c
|
||||
state.c
|
||||
@@ -84,7 +74,6 @@ add_library(renderer_EGL STATIC
|
||||
texture.c
|
||||
texture_buffer.c
|
||||
texture_framebuffer.c
|
||||
texture_dmabuf.c
|
||||
model.c
|
||||
desktop.c
|
||||
desktop_rects.c
|
||||
@@ -95,6 +84,7 @@ add_library(renderer_EGL STATIC
|
||||
framebuffer.c
|
||||
effect.c
|
||||
postprocess.c
|
||||
postprocess_order.c
|
||||
ffx.c
|
||||
filter_glsl.c
|
||||
filter_24bit.c
|
||||
@@ -106,19 +96,22 @@ add_library(renderer_EGL STATIC
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/shader/desktop_rgb.def.h"
|
||||
)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
list(APPEND RENDERER_EGL_SOURCES texture_dmabuf.c)
|
||||
else()
|
||||
list(APPEND RENDERER_EGL_SOURCES texture_dmabuf_stub.c)
|
||||
endif()
|
||||
|
||||
add_library(renderer_EGL STATIC ${RENDERER_EGL_SOURCES})
|
||||
|
||||
target_compile_definitions(renderer_EGL PRIVATE CIMGUI_DEFINE_ENUMS_AND_STRUCTS=1 IMGUI_IMPL_OPENGL_ES3)
|
||||
|
||||
target_link_libraries(renderer_EGL
|
||||
PkgConfig::RENDERER_EGL
|
||||
lg_egl_provider
|
||||
lg_common
|
||||
|
||||
lg_gui
|
||||
)
|
||||
if(RENDERER_EGL_OPT_FOUND)
|
||||
target_link_libraries(renderer_EGL
|
||||
PkgConfig::RENDERER_EGL_OPT
|
||||
)
|
||||
endif()
|
||||
|
||||
target_include_directories(renderer_EGL
|
||||
PRIVATE
|
||||
|
||||
@@ -424,13 +424,6 @@ bool egl_desktopUpdate(EGL_Desktop * desktop,
|
||||
|
||||
desktop->useDMA = false;
|
||||
|
||||
const char * gl_exts = (const char *)glGetString(GL_EXTENSIONS);
|
||||
if (!util_hasGLExt(gl_exts, "GL_EXT_buffer_storage"))
|
||||
{
|
||||
DEBUG_ERROR("GL_EXT_buffer_storage is needed to use EGL backend");
|
||||
return false;
|
||||
}
|
||||
|
||||
egl_textureFree(&desktop->texture);
|
||||
if (!egl_textureInit(&desktop->texture, desktop->display,
|
||||
EGL_TEXTYPE_FRAMEBUFFER))
|
||||
|
||||
@@ -38,14 +38,18 @@
|
||||
#include "cimgui.h"
|
||||
#include "cimgui_impl.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "egl_dynprocs.h"
|
||||
#include "egldebug.h"
|
||||
#include "model.h"
|
||||
#include "shader.h"
|
||||
#include "state.h"
|
||||
#include "texture.h"
|
||||
#include "texture_util.h"
|
||||
#include "damage.h"
|
||||
#include "desktop.h"
|
||||
#include "cursor.h"
|
||||
@@ -267,7 +271,8 @@ static bool egl_create(LG_Renderer ** renderer, const LG_RendererParams params,
|
||||
struct Inst * this = calloc(1, sizeof(*this));
|
||||
if (!this)
|
||||
{
|
||||
DEBUG_INFO("Failed to allocate %lu bytes", sizeof(*this));
|
||||
DEBUG_INFO("Failed to allocate %" PRIu64 " bytes",
|
||||
(uint64_t)sizeof(*this));
|
||||
return false;
|
||||
}
|
||||
*renderer = &this->base;
|
||||
@@ -776,8 +781,14 @@ static bool egl_onFrameFormat(LG_Renderer * renderer, const LG_RendererFormat fo
|
||||
/* this event runs in a second thread so we need to init it here */
|
||||
if (unlikely(!this->frameContext))
|
||||
{
|
||||
if (!eglBindAPI(EGL_OPENGL_ES_API))
|
||||
{
|
||||
DEBUG_EGL_ERROR("Failed to select the OpenGL ES API for frame uploads");
|
||||
return false;
|
||||
}
|
||||
|
||||
static EGLint attrs[] = {
|
||||
EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||
EGL_CONTEXT_CLIENT_VERSION, 3,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
@@ -1005,6 +1016,12 @@ static bool egl_renderStartup(LG_Renderer * renderer, bool useDMA)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!eglBindAPI(EGL_OPENGL_ES_API))
|
||||
{
|
||||
DEBUG_EGL_ERROR("Failed to select the OpenGL ES API");
|
||||
return false;
|
||||
}
|
||||
|
||||
int maxSamples = 1;
|
||||
if (option_get_bool("egl", "multisample"))
|
||||
{
|
||||
@@ -1063,7 +1080,7 @@ static bool egl_renderStartup(LG_Renderer * renderer, bool useDMA)
|
||||
EGL_CONFIG_ATTR(EGL_BUFFER_SIZE , configs[i].depth);
|
||||
if (hasFloatConfigs)
|
||||
EGL_CONFIG_ATTR(EGL_COLOR_COMPONENT_TYPE_EXT, configs[i].componentType);
|
||||
EGL_CONFIG_ATTR(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT);
|
||||
EGL_CONFIG_ATTR(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT);
|
||||
EGL_CONFIG_ATTR(EGL_SAMPLE_BUFFERS , maxSamples > 0 ? 1 : 0);
|
||||
EGL_CONFIG_ATTR(EGL_SAMPLES , maxSamples);
|
||||
attr[ai] = EGL_NONE;
|
||||
@@ -1125,7 +1142,7 @@ static bool egl_renderStartup(LG_Renderer * renderer, bool useDMA)
|
||||
int ctxidx = 0;
|
||||
|
||||
ctxattr[ctxidx++] = EGL_CONTEXT_CLIENT_VERSION;
|
||||
ctxattr[ctxidx++] = 2;
|
||||
ctxattr[ctxidx++] = 3;
|
||||
|
||||
if (maj > 1 || (maj == 1 && min >= 5))
|
||||
{
|
||||
@@ -1166,8 +1183,27 @@ static bool egl_renderStartup(LG_Renderer * renderer, bool useDMA)
|
||||
break;
|
||||
}
|
||||
|
||||
eglMakeCurrent(this->display, this->surface, this->surface, this->context);
|
||||
if (!eglMakeCurrent(this->display, this->surface, this->surface,
|
||||
this->context))
|
||||
{
|
||||
DEBUG_EGL_ERROR("Failed to make the EGL context current");
|
||||
return false;
|
||||
}
|
||||
|
||||
egl_stateInvalidate();
|
||||
egl_dynProcsInit();
|
||||
|
||||
GLint esMaj = 0;
|
||||
GLint esMin = 0;
|
||||
glGetIntegerv(GL_MAJOR_VERSION, &esMaj);
|
||||
glGetIntegerv(GL_MINOR_VERSION, &esMin);
|
||||
if (esMaj < 3)
|
||||
{
|
||||
DEBUG_ERROR("OpenGL ES 3.0 or newer is required, got %d.%d",
|
||||
esMaj, esMin);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char * gl_exts = (const char *)glGetString(GL_EXTENSIONS);
|
||||
if (!gl_exts)
|
||||
{
|
||||
@@ -1194,10 +1230,6 @@ static bool egl_renderStartup(LG_Renderer * renderer, bool useDMA)
|
||||
DEBUG_INFO("GL Exts : %s", gl_exts);
|
||||
}
|
||||
|
||||
GLint esMaj, esMin;
|
||||
glGetIntegerv(GL_MAJOR_VERSION, &esMaj);
|
||||
glGetIntegerv(GL_MINOR_VERSION, &esMin);
|
||||
|
||||
if (!util_hasGLExt(gl_exts, "GL_EXT_texture_format_BGRA8888"))
|
||||
{
|
||||
DEBUG_ERROR("GL_EXT_texture_format_BGRA8888 is needed to use EGL backend");
|
||||
@@ -1229,26 +1261,17 @@ static bool egl_renderStartup(LG_Renderer * renderer, bool useDMA)
|
||||
|
||||
this->scalePointer = option_get_bool("egl", "scalePointer");
|
||||
|
||||
if (!g_egl_dynProcs.glEGLImageTargetTexture2DOES)
|
||||
DEBUG_INFO("glEGLImageTargetTexture2DOES unavilable, DMA support disabled");
|
||||
else if (!g_egl_dynProcs.eglCreateImage || !g_egl_dynProcs.eglDestroyImage)
|
||||
DEBUG_INFO("eglCreateImage or eglDestroyImage unavailable, DMA support disabled");
|
||||
else if (!util_hasGLExt(client_exts, "EGL_EXT_image_dma_buf_import"))
|
||||
DEBUG_INFO("EGL_EXT_image_dma_buf_import unavailable, DMA support disabled");
|
||||
else if ((maj < 1 || (maj == 1 && min < 5)) && !util_hasGLExt(client_exts, "EGL_KHR_image_base"))
|
||||
DEBUG_INFO("Need EGL 1.5+ or EGL_KHR_image_base for eglCreateImage(KHR)");
|
||||
else
|
||||
this->dmaSupport = true;
|
||||
|
||||
this->dmaSupport = egl_texDMABUFSupported(this->display, maj, min);
|
||||
if (!this->dmaSupport)
|
||||
{
|
||||
useDMA = false;
|
||||
if (!util_hasGLExt(gl_exts, "GL_EXT_buffer_storage"))
|
||||
{
|
||||
DEBUG_ERROR("GL_EXT_buffer_storage is needed to use EGL backend");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const bool persistentUploads =
|
||||
util_hasGLExt(gl_exts, "GL_EXT_buffer_storage") &&
|
||||
g_egl_dynProcs.glBufferStorageEXT;
|
||||
egl_texUtilSetBufferMode(persistentUploads ?
|
||||
EGL_TEX_BUFFER_MODE_PERSISTENT : EGL_TEX_BUFFER_MODE_DIRECT);
|
||||
DEBUG_INFO("Texture upload method: %s",
|
||||
persistentUploads ? "persistent PBO" : "direct");
|
||||
|
||||
if (debug)
|
||||
{
|
||||
|
||||
@@ -18,14 +18,13 @@
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include "postprocess.h"
|
||||
#include "postprocess_order.h"
|
||||
#include "filters.h"
|
||||
#include "app.h"
|
||||
#include "cimgui.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include "common/debug.h"
|
||||
@@ -252,24 +251,6 @@ static bool savePreset(struct EGL_PostProcess * this, const char * name)
|
||||
return true;
|
||||
}
|
||||
|
||||
static int stringListIndex(StringList list, const char * str)
|
||||
{
|
||||
unsigned int count = stringlist_count(list);
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
if (strcmp(stringlist_at(list, i), str) == 0)
|
||||
return i;
|
||||
return INT_MAX;
|
||||
}
|
||||
|
||||
static int compareFilterOrder(const void * a_, const void * b_, void * opaque)
|
||||
{
|
||||
const EGL_Filter * a = *(const EGL_Filter **)a_;
|
||||
const EGL_Filter * b = *(const EGL_Filter **)b_;
|
||||
StringList order = opaque;
|
||||
|
||||
return stringListIndex(order, a->ops.id) - stringListIndex(order, b->ops.id);
|
||||
}
|
||||
|
||||
static void reorderFilters(struct EGL_PostProcess * this)
|
||||
{
|
||||
StringList order = stringlist_new(false);
|
||||
@@ -305,8 +286,9 @@ static void reorderFilters(struct EGL_PostProcess * this)
|
||||
p = end + 1;
|
||||
}
|
||||
|
||||
qsort_r(vector_data(&this->filters), vector_size(&this->filters),
|
||||
sizeof(EGL_Filter *), compareFilterOrder, order);
|
||||
EGL_Filter ** filters = vector_data(&this->filters);
|
||||
const size_t count = vector_size(&this->filters);
|
||||
egl_postProcessOrderFilters(filters, count, order);
|
||||
|
||||
stringlist_free(&order);
|
||||
free(orderStr);
|
||||
|
||||
57
client/renderers/EGL/postprocess_order.c
Normal file
57
client/renderers/EGL/postprocess_order.c
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "postprocess_order.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
static unsigned int stringListIndex(StringList list, const char * str)
|
||||
{
|
||||
const unsigned int count = stringlist_count(list);
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
if (strcmp(stringlist_at(list, i), str) == 0)
|
||||
return i;
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
static bool filterAfter(const EGL_Filter * a, const EGL_Filter * b,
|
||||
StringList order)
|
||||
{
|
||||
const unsigned int aIndex = stringListIndex(order, a->ops.id);
|
||||
const unsigned int bIndex = stringListIndex(order, b->ops.id);
|
||||
return aIndex > bIndex;
|
||||
}
|
||||
|
||||
void egl_postProcessOrderFilters(EGL_Filter ** filters, size_t count,
|
||||
StringList order)
|
||||
{
|
||||
for (size_t i = 1; i < count; ++i)
|
||||
{
|
||||
EGL_Filter * filter = filters[i];
|
||||
size_t j = i;
|
||||
while (j > 0 && filterAfter(filters[j - 1], filter, order))
|
||||
{
|
||||
filters[j] = filters[j - 1];
|
||||
--j;
|
||||
}
|
||||
filters[j] = filter;
|
||||
}
|
||||
}
|
||||
30
client/renderers/EGL/postprocess_order.h
Normal file
30
client/renderers/EGL/postprocess_order.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "filter.h"
|
||||
|
||||
#include "common/stringlist.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
void egl_postProcessOrderFilters(EGL_Filter ** filters, size_t count,
|
||||
StringList order);
|
||||
@@ -36,7 +36,6 @@
|
||||
extern const EGL_TextureOps EGL_TextureBuffer;
|
||||
extern const EGL_TextureOps EGL_TextureBufferStream;
|
||||
extern const EGL_TextureOps EGL_TextureFrameBuffer;
|
||||
extern const EGL_TextureOps EGL_TextureDMABUF;
|
||||
|
||||
bool egl_textureInit(EGL_Texture ** texture_, EGLDisplay * display,
|
||||
EGL_TexType type)
|
||||
|
||||
@@ -125,6 +125,9 @@ struct EGL_Texture
|
||||
EGL_TexFormat format;
|
||||
};
|
||||
|
||||
extern const EGL_TextureOps EGL_TextureDMABUF;
|
||||
bool egl_texDMABUFSupported(EGLDisplay display, EGLint major, EGLint minor);
|
||||
|
||||
bool egl_textureInit(EGL_Texture ** texture, EGLDisplay * display,
|
||||
EGL_TexType type);
|
||||
void egl_textureFree(EGL_Texture ** tex);
|
||||
|
||||
@@ -454,14 +454,17 @@ EGL_TexStatus egl_texBufferStreamProcess(EGL_Texture * texture,
|
||||
this->bufIndex = 0;
|
||||
buffer->updated = false;
|
||||
|
||||
/* With more than one slot the producer can fill the next PBO while this
|
||||
* upload is queued. A single-slot texture must remain locked until its
|
||||
* fence exists so the mapped buffer cannot be overwritten concurrently. */
|
||||
/* With more than one slot the producer can fill the next upload buffer
|
||||
* while this one is submitted. Keep a single-slot texture locked until the
|
||||
* upload is issued and, for persistent storage, its fence exists. */
|
||||
const bool keepLocked = this->texCount == 1;
|
||||
if (!keepLocked)
|
||||
LG_UNLOCK(this->copyLock);
|
||||
|
||||
egl_stateBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer->pbo);
|
||||
const bool persistent =
|
||||
buffer->mode == EGL_TEX_BUFFER_MODE_PERSISTENT;
|
||||
egl_stateBindBuffer(GL_PIXEL_UNPACK_BUFFER,
|
||||
persistent ? buffer->pbo : 0);
|
||||
egl_stateBindTexture(0, GL_TEXTURE_2D, tex);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
@@ -475,7 +478,7 @@ EGL_TexStatus egl_texBufferStreamProcess(EGL_Texture * texture,
|
||||
texture->format.height,
|
||||
texture->format.format,
|
||||
texture->format.dataType,
|
||||
(const void *)0);
|
||||
persistent ? (const void *)0 : buffer->map);
|
||||
else
|
||||
for (int i = 0; i < damage->count; ++i)
|
||||
{
|
||||
@@ -491,11 +494,19 @@ EGL_TexStatus egl_texBufferStreamProcess(EGL_Texture * texture,
|
||||
rect->height,
|
||||
texture->format.format,
|
||||
texture->format.dataType,
|
||||
(const void *)offset);
|
||||
persistent ? (const void *)offset :
|
||||
(const uint8_t *)buffer->map + offset);
|
||||
}
|
||||
|
||||
/* Keep damage intact until all of its upload commands have been issued. */
|
||||
egl_texBufferDamageReset(damage);
|
||||
if (!persistent)
|
||||
{
|
||||
if (keepLocked)
|
||||
LG_UNLOCK(this->copyLock);
|
||||
return EGL_TEX_STATUS_UPDATED;
|
||||
}
|
||||
|
||||
this->sync[index] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
if (unlikely(!this->sync[index]))
|
||||
{
|
||||
|
||||
@@ -86,12 +86,32 @@ struct SnapshotRelease
|
||||
uint64_t handle;
|
||||
};
|
||||
|
||||
EGL_TextureOps EGL_TextureDMABUF;
|
||||
const EGL_TextureOps EGL_TextureDMABUF;
|
||||
|
||||
static bool initDone = false;
|
||||
static bool has24BitSupport = true;
|
||||
static bool hasImportModifiers = true;
|
||||
|
||||
bool egl_texDMABUFSupported(EGLDisplay display, EGLint major, EGLint minor)
|
||||
{
|
||||
const char * extensions = eglQueryString(display, EGL_EXTENSIONS);
|
||||
|
||||
if (!g_egl_dynProcs.glEGLImageTargetTexture2DOES)
|
||||
DEBUG_INFO("glEGLImageTargetTexture2DOES unavailable, DMA support disabled");
|
||||
else if (!g_egl_dynProcs.eglCreateImage || !g_egl_dynProcs.eglDestroyImage)
|
||||
DEBUG_INFO("eglCreateImage or eglDestroyImage unavailable, DMA support disabled");
|
||||
else if (!extensions ||
|
||||
!util_hasGLExt(extensions, "EGL_EXT_image_dma_buf_import"))
|
||||
DEBUG_INFO("EGL_EXT_image_dma_buf_import unavailable, DMA support disabled");
|
||||
else if ((major < 1 || (major == 1 && minor < 5)) &&
|
||||
!util_hasGLExt(extensions, "EGL_KHR_image_base"))
|
||||
DEBUG_INFO("Need EGL 1.5+ or EGL_KHR_image_base for eglCreateImage(KHR)");
|
||||
else
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// internal functions
|
||||
|
||||
static void egl_texDMABUFFree(EGL_Texture * texture);
|
||||
@@ -695,7 +715,7 @@ static void egl_texDMABUFMarkUsed(EGL_Texture * texture)
|
||||
LG_UNLOCK(parent->copyLock);
|
||||
}
|
||||
|
||||
EGL_TextureOps EGL_TextureDMABUF =
|
||||
const EGL_TextureOps EGL_TextureDMABUF =
|
||||
{
|
||||
.init = egl_texDMABUFInit,
|
||||
.free = egl_texDMABUFFree,
|
||||
|
||||
43
client/renderers/EGL/texture_dmabuf_stub.c
Normal file
43
client/renderers/EGL/texture_dmabuf_stub.c
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "texture.h"
|
||||
|
||||
static bool egl_texDMABUFInitUnsupported(EGL_Texture ** texture,
|
||||
EGL_TexType type, EGLDisplay * display)
|
||||
{
|
||||
(void)texture;
|
||||
(void)type;
|
||||
(void)display;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool egl_texDMABUFSupported(EGLDisplay display, EGLint major, EGLint minor)
|
||||
{
|
||||
(void)display;
|
||||
(void)major;
|
||||
(void)minor;
|
||||
return false;
|
||||
}
|
||||
|
||||
const EGL_TextureOps EGL_TextureDMABUF =
|
||||
{
|
||||
.init = egl_texDMABUFInitUnsupported,
|
||||
};
|
||||
@@ -29,6 +29,11 @@
|
||||
#include "egldebug.h"
|
||||
#include "egl_dynprocs.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static EGL_TexBufferMode bufferMode = EGL_TEX_BUFFER_MODE_DIRECT;
|
||||
|
||||
bool egl_texUtilGetFormat(const EGL_TexSetup * setup, EGL_TexFormat * fmt)
|
||||
{
|
||||
fmt->pixFmt = setup->pixFmt;
|
||||
@@ -37,7 +42,7 @@ bool egl_texUtilGetFormat(const EGL_TexSetup * setup, EGL_TexFormat * fmt)
|
||||
fmt->stride = setup->stride;
|
||||
fmt->pitch = setup->pitch;
|
||||
|
||||
switch(setup->pixFmt)
|
||||
switch (setup->pixFmt)
|
||||
{
|
||||
case EGL_PF_BGRA:
|
||||
fmt->bpp = 4;
|
||||
@@ -104,14 +109,33 @@ bool egl_texUtilGetFormat(const EGL_TexSetup * setup, EGL_TexFormat * fmt)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool egl_texUtilGenBuffers(const EGL_TexFormat * fmt, EGL_TexBuffer * buffers,
|
||||
int count)
|
||||
void egl_texUtilSetBufferMode(EGL_TexBufferMode mode)
|
||||
{
|
||||
for(int i = 0; i < count; ++i)
|
||||
bufferMode = mode;
|
||||
}
|
||||
|
||||
static bool egl_texUtilGenBuffersMode(const EGL_TexFormat * fmt,
|
||||
EGL_TexBuffer * buffers, int count, EGL_TexBufferMode mode)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
EGL_TexBuffer *buffer = &buffers[i];
|
||||
EGL_TexBuffer * buffer = &buffers[i];
|
||||
|
||||
buffer->size = fmt->dataSize;
|
||||
buffer->mode = mode;
|
||||
if (mode == EGL_TEX_BUFFER_MODE_DIRECT)
|
||||
{
|
||||
buffer->map = malloc(buffer->size);
|
||||
if (!buffer->map)
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate %" PRIu64
|
||||
"-byte texture upload buffer", (uint64_t)buffer->size);
|
||||
return false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
glGenBuffers(1, &buffer->pbo);
|
||||
egl_stateBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer->pbo);
|
||||
g_egl_dynProcs.glBufferStorageEXT(
|
||||
@@ -130,12 +154,47 @@ bool egl_texUtilGenBuffers(const EGL_TexFormat * fmt, EGL_TexBuffer * buffers,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool egl_texUtilGenBuffers(const EGL_TexFormat * fmt, EGL_TexBuffer * buffers,
|
||||
int count)
|
||||
{
|
||||
EGL_TexBufferMode mode = bufferMode;
|
||||
if (mode == EGL_TEX_BUFFER_MODE_PERSISTENT &&
|
||||
!g_egl_dynProcs.glBufferStorageEXT)
|
||||
{
|
||||
DEBUG_WARN("Persistent texture uploads unavailable, using direct uploads");
|
||||
mode = EGL_TEX_BUFFER_MODE_DIRECT;
|
||||
}
|
||||
|
||||
if (egl_texUtilGenBuffersMode(fmt, buffers, count, mode))
|
||||
return true;
|
||||
|
||||
egl_texUtilFreeBuffers(buffers, count);
|
||||
if (mode != EGL_TEX_BUFFER_MODE_PERSISTENT)
|
||||
return false;
|
||||
|
||||
DEBUG_WARN("Persistent texture upload buffers failed, using direct uploads");
|
||||
mode = EGL_TEX_BUFFER_MODE_DIRECT;
|
||||
if (egl_texUtilGenBuffersMode(fmt, buffers, count, mode))
|
||||
return true;
|
||||
|
||||
egl_texUtilFreeBuffers(buffers, count);
|
||||
return false;
|
||||
}
|
||||
|
||||
void egl_texUtilFreeBuffers(EGL_TexBuffer * buffers, int count)
|
||||
{
|
||||
bool deleted = false;
|
||||
for(int i = 0; i < count; ++i)
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
EGL_TexBuffer *buffer = &buffers[i];
|
||||
EGL_TexBuffer * buffer = &buffers[i];
|
||||
|
||||
if (buffer->mode == EGL_TEX_BUFFER_MODE_DIRECT)
|
||||
{
|
||||
free(buffer->map);
|
||||
buffer->map = NULL;
|
||||
buffer->size = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!buffer->pbo)
|
||||
continue;
|
||||
@@ -143,7 +202,8 @@ void egl_texUtilFreeBuffers(EGL_TexBuffer * buffers, int count)
|
||||
egl_texUtilUnmapBuffer(buffer);
|
||||
glDeleteBuffers(1, &buffer->pbo);
|
||||
deleted = true;
|
||||
buffer->pbo = 0;
|
||||
buffer->pbo = 0;
|
||||
buffer->size = 0;
|
||||
}
|
||||
|
||||
if (deleted)
|
||||
@@ -152,6 +212,7 @@ void egl_texUtilFreeBuffers(EGL_TexBuffer * buffers, int count)
|
||||
|
||||
bool egl_texUtilMapBuffer(EGL_TexBuffer * buffer)
|
||||
{
|
||||
DEBUG_ASSERT(buffer->mode == EGL_TEX_BUFFER_MODE_PERSISTENT);
|
||||
egl_stateBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer->pbo);
|
||||
buffer->map = glMapBufferRange(
|
||||
GL_PIXEL_UNPACK_BUFFER,
|
||||
@@ -164,7 +225,8 @@ bool egl_texUtilMapBuffer(EGL_TexBuffer * buffer)
|
||||
GL_MAP_COHERENT_BIT_EXT);
|
||||
|
||||
if (!buffer->map)
|
||||
DEBUG_GL_ERROR("glMapBufferRange failed of %lu bytes", buffer->size);
|
||||
DEBUG_GL_ERROR("glMapBufferRange failed of %" PRIu64 " bytes",
|
||||
(uint64_t)buffer->size);
|
||||
|
||||
egl_stateBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
return buffer->map;
|
||||
@@ -175,6 +237,7 @@ void egl_texUtilUnmapBuffer(EGL_TexBuffer * buffer)
|
||||
if (!buffer->map)
|
||||
return;
|
||||
|
||||
DEBUG_ASSERT(buffer->mode == EGL_TEX_BUFFER_MODE_PERSISTENT);
|
||||
egl_stateBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer->pbo);
|
||||
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
|
||||
egl_stateBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
|
||||
@@ -40,16 +40,25 @@ typedef struct EGL_TexFormat
|
||||
}
|
||||
EGL_TexFormat;
|
||||
|
||||
typedef enum EGL_TexBufferMode
|
||||
{
|
||||
EGL_TEX_BUFFER_MODE_DIRECT,
|
||||
EGL_TEX_BUFFER_MODE_PERSISTENT
|
||||
}
|
||||
EGL_TexBufferMode;
|
||||
|
||||
typedef struct EGL_TexBuffer
|
||||
{
|
||||
size_t size;
|
||||
GLuint pbo;
|
||||
void * map;
|
||||
bool updated;
|
||||
size_t size;
|
||||
GLuint pbo;
|
||||
void * map;
|
||||
bool updated;
|
||||
EGL_TexBufferMode mode;
|
||||
}
|
||||
EGL_TexBuffer;
|
||||
|
||||
bool egl_texUtilGetFormat(const EGL_TexSetup * setup, EGL_TexFormat * fmt);
|
||||
void egl_texUtilSetBufferMode(EGL_TexBufferMode mode);
|
||||
bool egl_texUtilGenBuffers(const EGL_TexFormat * fmt, EGL_TexBuffer * buffers,
|
||||
int count);
|
||||
void egl_texUtilFreeBuffers(EGL_TexBuffer * buffers, int count);
|
||||
|
||||
Reference in New Issue
Block a user