From f1141664b6756a3ba12f867d0ccc23adb7c60287 Mon Sep 17 00:00:00 2001 From: bjorn Date: Sat, 22 Jul 2017 18:15:03 -0700 Subject: [PATCH] Mipmap generation; --- src/graphics/texture.c | 42 +++++++++++++++++++++++++++++++++++++++--- src/headset/openvr.c | 6 +++--- src/lib/glad/glad.c | 17 ++++++++++++++--- src/lib/glad/glad.h | 14 +++++++++++--- src/loaders/texture.c | 29 ++++++++++++++++++++++------- src/loaders/texture.h | 5 ++++- 6 files changed, 93 insertions(+), 20 deletions(-) diff --git a/src/graphics/texture.c b/src/graphics/texture.c index 1adb3adc..ee25df26 100644 --- a/src/graphics/texture.c +++ b/src/graphics/texture.c @@ -5,6 +5,29 @@ #include #include +static void lovrTextureCreateStorage(Texture* texture) { + TextureData* textureData = texture->textureData; + + if (textureData->format.compressed || !textureData->mipmaps.generated) { + return; + } + + int w = textureData->width; + int h = textureData->height; + int mipmapCount = log2(MAX(w, h)) + 1; + GLenum internalFormat = textureData->format.glInternalFormat; + GLenum format = textureData->format.glFormat; + if (GLAD_GL_ARB_texture_storage) { + glTexStorage2D(GL_TEXTURE_2D, mipmapCount, internalFormat, w, h); + } else { + for (int i = 0; i < mipmapCount; i++) { + glTexImage2D(GL_TEXTURE_2D, i, internalFormat, w, h, 0, format, GL_UNSIGNED_BYTE, NULL); + w = MAX(w >> 1, 1); + h = MAX(h >> 1, 1); + } + } +} + Texture* lovrTextureCreate(TextureData* textureData) { Texture* texture = lovrAlloc(sizeof(Texture), lovrTextureDestroy); if (!texture) return NULL; @@ -13,6 +36,8 @@ Texture* lovrTextureCreate(TextureData* textureData) { texture->depthBuffer = 0; texture->textureData = textureData; glGenTextures(1, &texture->id); + lovrGraphicsBindTexture(texture); + lovrTextureCreateStorage(texture); lovrTextureRefresh(texture); lovrTextureSetFilter(texture, FILTER_LINEAR, FILTER_LINEAR); lovrTextureSetWrap(texture, WRAP_REPEAT, WRAP_REPEAT); @@ -132,12 +157,23 @@ void lovrTextureResolveMSAA(Texture* texture) { void lovrTextureRefresh(Texture* texture) { TextureData* textureData = texture->textureData; - int w = textureData->width; - int h = textureData->height; GLenum glInternalFormat = textureData->format.glInternalFormat; GLenum glFormat = textureData->format.glFormat; lovrGraphicsBindTexture(texture); - glTexImage2D(GL_TEXTURE_2D, 0, glInternalFormat, w, h, 0, glFormat, GL_UNSIGNED_BYTE, textureData->data); + + if (textureData->format.compressed) { + Mipmap m; int i; + vec_foreach(&textureData->mipmaps.list, m, i) { + glCompressedTexImage2D(GL_TEXTURE_2D, i, glInternalFormat, m.width, m.height, 0, m.size, m.data); + } + } else { + int w = textureData->width; + int h = textureData->height; + glTexImage2D(GL_TEXTURE_2D, 0, glInternalFormat, w, h, 0, glFormat, GL_UNSIGNED_BYTE, textureData->data); + if (textureData->mipmaps.generated) { + glGenerateMipmap(GL_TEXTURE_2D); + } + } } int lovrTextureGetHeight(Texture* texture) { diff --git a/src/headset/openvr.c b/src/headset/openvr.c index 3c0f7eff..ffd873ac 100644 --- a/src/headset/openvr.c +++ b/src/headset/openvr.c @@ -589,9 +589,9 @@ TextureData* lovrHeadsetControllerNewTextureData(Controller* controller) { textureData->width = width; textureData->height = height; textureData->format = format; - textureData->data = malloc(size); - memcpy(textureData->data, vrTexture->rubTextureMapData, size); - + textureData->data = memcpy(malloc(size), vrTexture->rubTextureMapData, size);; + textureData->mipmaps.generated = 1; + textureData->blob = NULL; return textureData; } diff --git a/src/lib/glad/glad.c b/src/lib/glad/glad.c index 2832cab1..adea296c 100644 --- a/src/lib/glad/glad.c +++ b/src/lib/glad/glad.c @@ -1,12 +1,13 @@ /* - OpenGL, OpenGL ES loader generated by glad 0.1.14a0 on Sat Jul 22 10:22:59 2017. + OpenGL, OpenGL ES loader generated by glad 0.1.14a0 on Sun Jul 23 03:01:38 2017. Language/Generator: C/C++ Specification: gl APIs: gl=3.3, gles2=3.0 Profile: core Extensions: + GL_ARB_texture_storage, GL_EXT_texture_compression_s3tc, GL_EXT_texture_filter_anisotropic Loader: False @@ -14,9 +15,9 @@ Omit khrplatform: False Commandline: - --profile="core" --api="gl=3.3,gles2=3.0" --generator="c" --spec="gl" --no-loader --extensions="GL_EXT_texture_compression_s3tc,GL_EXT_texture_filter_anisotropic" + --profile="core" --api="gl=3.3,gles2=3.0" --generator="c" --spec="gl" --no-loader --extensions="GL_ARB_texture_storage,GL_EXT_texture_compression_s3tc,GL_EXT_texture_filter_anisotropic" Online: - http://glad.dav1d.de/#profile=core&language=c&specification=gl&api=gl%3D3.3&api=gles2%3D3.0&extensions=GL_EXT_texture_compression_s3tc&extensions=GL_EXT_texture_filter_anisotropic + http://glad.dav1d.de/#profile=core&language=c&specification=gl&api=gl%3D3.3&api=gles2%3D3.0&extensions=GL_ARB_texture_storage&extensions=GL_EXT_texture_compression_s3tc&extensions=GL_EXT_texture_filter_anisotropic */ #include @@ -519,8 +520,10 @@ PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex; PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample; PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; PFNGLFRONTFACEPROC glad_glFrontFace; +int GLAD_GL_ARB_texture_storage; int GLAD_GL_EXT_texture_compression_s3tc; int GLAD_GL_EXT_texture_filter_anisotropic; +PFNGLTEXSTORAGE1DPROC glad_glTexStorage1D; static void load_GL_VERSION_1_0(GLADloadproc load) { if(!GLAD_GL_VERSION_1_0) return; glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace"); @@ -934,8 +937,15 @@ static void load_GL_VERSION_3_3(GLADloadproc load) { glad_glSecondaryColorP3ui = (PFNGLSECONDARYCOLORP3UIPROC)load("glSecondaryColorP3ui"); glad_glSecondaryColorP3uiv = (PFNGLSECONDARYCOLORP3UIVPROC)load("glSecondaryColorP3uiv"); } +static void load_GL_ARB_texture_storage(GLADloadproc load) { + if(!GLAD_GL_ARB_texture_storage) return; + glad_glTexStorage1D = (PFNGLTEXSTORAGE1DPROC)load("glTexStorage1D"); + glad_glTexStorage2D = (PFNGLTEXSTORAGE2DPROC)load("glTexStorage2D"); + glad_glTexStorage3D = (PFNGLTEXSTORAGE3DPROC)load("glTexStorage3D"); +} static int find_extensionsGL(void) { if (!get_exts()) return 0; + GLAD_GL_ARB_texture_storage = has_ext("GL_ARB_texture_storage"); GLAD_GL_EXT_texture_compression_s3tc = has_ext("GL_EXT_texture_compression_s3tc"); GLAD_GL_EXT_texture_filter_anisotropic = has_ext("GL_EXT_texture_filter_anisotropic"); free_exts(); @@ -1016,6 +1026,7 @@ int gladLoadGLLoader(GLADloadproc load) { load_GL_VERSION_3_3(load); if (!find_extensionsGL()) return 0; + load_GL_ARB_texture_storage(load); return GLVersion.major != 0 || GLVersion.minor != 0; } diff --git a/src/lib/glad/glad.h b/src/lib/glad/glad.h index 646bd9f8..d6e26229 100644 --- a/src/lib/glad/glad.h +++ b/src/lib/glad/glad.h @@ -1,12 +1,13 @@ /* - OpenGL, OpenGL ES loader generated by glad 0.1.14a0 on Sat Jul 22 10:22:59 2017. + OpenGL, OpenGL ES loader generated by glad 0.1.14a0 on Sun Jul 23 03:01:38 2017. Language/Generator: C/C++ Specification: gl APIs: gl=3.3, gles2=3.0 Profile: core Extensions: + GL_ARB_texture_storage, GL_EXT_texture_compression_s3tc, GL_EXT_texture_filter_anisotropic Loader: False @@ -14,9 +15,9 @@ Omit khrplatform: False Commandline: - --profile="core" --api="gl=3.3,gles2=3.0" --generator="c" --spec="gl" --no-loader --extensions="GL_EXT_texture_compression_s3tc,GL_EXT_texture_filter_anisotropic" + --profile="core" --api="gl=3.3,gles2=3.0" --generator="c" --spec="gl" --no-loader --extensions="GL_ARB_texture_storage,GL_EXT_texture_compression_s3tc,GL_EXT_texture_filter_anisotropic" Online: - http://glad.dav1d.de/#profile=core&language=c&specification=gl&api=gl%3D3.3&api=gles2%3D3.0&extensions=GL_EXT_texture_compression_s3tc&extensions=GL_EXT_texture_filter_anisotropic + http://glad.dav1d.de/#profile=core&language=c&specification=gl&api=gl%3D3.3&api=gles2%3D3.0&extensions=GL_ARB_texture_storage&extensions=GL_EXT_texture_compression_s3tc&extensions=GL_EXT_texture_filter_anisotropic */ @@ -2297,6 +2298,13 @@ GLAPI PFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ; #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF +#ifndef GL_ARB_texture_storage +#define GL_ARB_texture_storage 1 +GLAPI int GLAD_GL_ARB_texture_storage; +typedef void (APIENTRYP PFNGLTEXSTORAGE1DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +GLAPI PFNGLTEXSTORAGE1DPROC glad_glTexStorage1D; +#define glTexStorage1D glad_glTexStorage1D +#endif #ifndef GL_EXT_texture_compression_s3tc #define GL_EXT_texture_compression_s3tc 1 GLAPI int GLAD_GL_EXT_texture_compression_s3tc; diff --git a/src/loaders/texture.c b/src/loaders/texture.c index b6858e58..a8020db8 100644 --- a/src/loaders/texture.c +++ b/src/loaders/texture.c @@ -121,7 +121,7 @@ static int parseDDS(uint8_t* data, size_t size, TextureData* textureData) { int mipmapCount = header->mipMapCount; // Load mipmaps - vec_init(&textureData->mipmaps); + vec_init(&textureData->mipmaps.list); for (int i = 0; i < mipmapCount; i++) { size_t numBlocksWide = width ? MAX(1, (width + 3) / 4) : 0; size_t numBlocksHigh = height ? MAX(1, (height + 3) / 4) : 0; @@ -129,15 +129,15 @@ static int parseDDS(uint8_t* data, size_t size, TextureData* textureData) { // Overflow check if (mipmapSize == 0 || (offset + mipmapSize) > size) { - vec_deinit(&textureData->mipmaps); + vec_deinit(&textureData->mipmaps.list); return 1; } Mipmap mipmap = { .width = width, .height = height, .data = &data[offset], .size = mipmapSize }; - vec_push(&textureData->mipmaps, mipmap); + vec_push(&textureData->mipmaps.list, mipmap); offset += mipmapSize; - width >>= 1; - height >>= 1; + width = MAX(width >> 1, 1); + height = MAX(height >> 1, 1); } textureData->data = NULL; @@ -153,8 +153,9 @@ TextureData* lovrTextureDataGetBlank(int width, int height, uint8_t value, Textu textureData->width = width; textureData->height = height; textureData->format = format; - textureData->data = malloc(size); - memset(textureData->data, value, size); + textureData->data = memset(malloc(size), value, size); + textureData->mipmaps.generated = 0; + textureData->blob = NULL; return textureData; } @@ -166,6 +167,8 @@ TextureData* lovrTextureDataGetEmpty(int width, int height, TextureFormat format textureData->height = height; textureData->format = format; textureData->data = NULL; + textureData->mipmaps.generated = 0; + textureData->blob = NULL; return textureData; } @@ -182,6 +185,8 @@ TextureData* lovrTextureDataFromBlob(Blob* blob) { stbi_set_flip_vertically_on_load(0); textureData->format = FORMAT_RGBA; textureData->data = stbi_load_from_memory(blob->data, blob->size, &textureData->width, &textureData->height, NULL, 4); + textureData->mipmaps.generated = 1; + textureData->blob = NULL; if (!textureData->data) { error("Could not load texture data from '%s'", blob->name); @@ -193,6 +198,10 @@ TextureData* lovrTextureDataFromBlob(Blob* blob) { } void lovrTextureDataResize(TextureData* textureData, int width, int height, uint8_t value) { + if (textureData->format.compressed || textureData->mipmaps.generated) { + error("Can't resize a compressed texture or a texture with generated mipmaps."); + } + int size = width * height * textureData->format.blockBytes; textureData->width = width; textureData->height = height; @@ -201,6 +210,12 @@ void lovrTextureDataResize(TextureData* textureData, int width, int height, uint } void lovrTextureDataDestroy(TextureData* textureData) { + if (textureData->blob) { + lovrRelease(&textureData->blob->ref); + } + if (textureData->format.compressed) { + vec_deinit(&textureData->mipmaps.list); + } free(textureData->data); free(textureData); } diff --git a/src/loaders/texture.h b/src/loaders/texture.h index c1cff024..65477d9e 100644 --- a/src/loaders/texture.h +++ b/src/loaders/texture.h @@ -27,7 +27,10 @@ typedef struct { int height; TextureFormat format; void* data; - vec_mipmap_t mipmaps; + union MipmapType { + vec_mipmap_t list; + int generated; + } mipmaps; Blob* blob; } TextureData;