[client] egl: add portable texture upload fallback

This commit is contained in:
Geoffrey McRae
2026-09-12 10:45:04 +10:00
parent 7ea69f3d1c
commit 18541865f0
17 changed files with 1010 additions and 116 deletions

View File

@@ -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

View File

@@ -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))

View File

@@ -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)
{

View File

@@ -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);

View 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;
}
}

View 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);

View File

@@ -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)

View File

@@ -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);

View File

@@ -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]))
{

View File

@@ -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,

View 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,
};

View File

@@ -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);

View File

@@ -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);