/* * gcc -DBROKEN textureSize-test.c -o textureSize-test `pkg-config --libs sdl2` `pkg-config --libs gl` && ./textureSize-test * uses previous texture: width: 2.000000 height 2.000000 miplevels 2.000000 * * gcc textureSize-test.c -o textureSize-test `pkg-config --libs sdl2` `pkg-config --libs gl` && ./textureSize-test * works correctly: width: 512.000000 height 256.000000 miplevels 4.000000 */ #include "SDL2/SDL.h" #include "GL/gl.h" #include "GL/glext.h" #include static const char *vertex_shader_source = "#version 130\n" "attribute vec4 in_position;\n" "void main()\n" "{\n" "gl_Position = in_position;\n" "}\n"; static const char *fragment_shader_source = "#version 130\n" "#extension GL_ARB_shader_bit_encoding : enable\n" "#extension GL_ARB_shader_texture_lod : enable\n" "#extension GL_ARB_texture_query_levels: enable\n" "#extension GL_ARB_uniform_buffer_object : enable\n" "uniform sampler2D ps_sampler0;\n" "vec4 R0;\n" "void main()\n" "{\n" "gl_FragData[0].xy = vec2(textureSize(ps_sampler0, 0));\n" "gl_FragData[0].z = float(textureQueryLevels(ps_sampler0));\n" "}\n"; static const float quad[] = { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, }; #define check_gl_call(call) check_gl_call_(call, __FILE__, __LINE__) static void check_gl_call_(const char *call, const char *file, unsigned int line) { GLint err; err = glGetError(); while (err != GL_NO_ERROR) { fprintf(stderr, "GL error %#x from %s @ %s / %d.\n", err, call, file, line); err = glGetError(); } } PFNGLGENBUFFERSPROC glGenBuffers; PFNGLBINDBUFFERPROC glBindBuffer; PFNGLBUFFERDATAPROC glBufferData; PFNGLGENSAMPLERSPROC glGenSamplers; PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D; PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus; PFNGLDRAWBUFFERSPROC glDrawBuffers; PFNGLCREATESHADERPROC glCreateShader; PFNGLSHADERSOURCEPROC glShaderSource; PFNGLCOMPILESHADERPROC glCompileShader; PFNGLGETSHADERIVPROC glGetShaderiv; PFNGLCREATEPROGRAMPROC glCreateProgram; PFNGLATTACHSHADERPROC glAttachShader; PFNGLLINKPROGRAMPROC glLinkProgram; PFNGLDETACHSHADERPROC glDetachShader; PFNGLGETPROGRAMIVPROC glGetProgramiv; PFNGLUSEPROGRAMPROC glUseProgram; PFNGLBINDSAMPLERPROC glBindSampler; PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; PFNGLMAPBUFFERPROC glMapBuffer; PFNGLUNMAPBUFFERPROC glUnmapBuffer; PFNGLDELETEBUFFERSPROC glDeleteBuffers; PFNGLDELETESAMPLERSPROC glDeleteSamplers; PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers; PFNGLDELETESHADERPROC glDeleteShader; PFNGLDELETEPROGRAMPROC glDeleteProgram; static void load_gl_procs(void) { glGenBuffers = SDL_GL_GetProcAddress("glGenBuffers"); glBindBuffer = SDL_GL_GetProcAddress("glBindBuffer"); glBufferData = SDL_GL_GetProcAddress("glBufferData"); glGenSamplers = SDL_GL_GetProcAddress("glGenSamplers"); glGenFramebuffers = SDL_GL_GetProcAddress("glGenFramebuffers"); glBindFramebuffer = SDL_GL_GetProcAddress("glBindFramebuffer"); glFramebufferTexture2D = SDL_GL_GetProcAddress("glFramebufferTexture2D"); glCheckFramebufferStatus = SDL_GL_GetProcAddress("glCheckFramebufferStatus"); glDrawBuffers = SDL_GL_GetProcAddress("glDrawBuffers"); glCreateShader = SDL_GL_GetProcAddress("glCreateShader"); glShaderSource = SDL_GL_GetProcAddress("glShaderSource"); glCompileShader = SDL_GL_GetProcAddress("glCompileShader"); glGetShaderiv = SDL_GL_GetProcAddress("glGetShaderiv"); glCreateProgram = SDL_GL_GetProcAddress("glCreateProgram"); glAttachShader = SDL_GL_GetProcAddress("glAttachShader"); glLinkProgram = SDL_GL_GetProcAddress("glLinkProgram"); glDetachShader = SDL_GL_GetProcAddress("glDetachShader"); glGetProgramiv = SDL_GL_GetProcAddress("glGetProgramiv"); glUseProgram = SDL_GL_GetProcAddress("glUseProgram"); glBindSampler = SDL_GL_GetProcAddress("glBindSampler"); glVertexAttribPointer = SDL_GL_GetProcAddress("glVertexAttribPointer"); glEnableVertexAttribArray = SDL_GL_GetProcAddress("glEnableVertexAttribArray"); glDeleteBuffers = SDL_GL_GetProcAddress("glDeleteBuffers"); glDeleteSamplers = SDL_GL_GetProcAddress("glDeleteSamplers"); glDeleteFramebuffers = SDL_GL_GetProcAddress("glDeleteFramebuffers"); glDeleteShader = SDL_GL_GetProcAddress("glDeleteShader"); glDeleteProgram = SDL_GL_GetProcAddress("glDeleteProgram"); glMapBuffer = SDL_GL_GetProcAddress("glMapBuffer"); glUnmapBuffer = SDL_GL_GetProcAddress("glUnmapBuffer"); } static void run_test(void) { GLuint buffer; GLuint sampler; GLuint render_target, texture; GLuint framebuffer; GLenum draw_buffers; GLuint fragment_shader; GLuint vertex_shader; GLuint program; GLint status; float *data; char blob[2097152] = {0}; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, 2, 2, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 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_WRAP_R, GL_CLAMP_TO_EDGE); glEnable(GL_TEXTURE_2D); #if BROKEN glBegin(GL_TRIANGLE_STRIP); glTexCoord2f(0.0, 0.0); glVertex2f(-1.0f, -1.0f); glTexCoord2f(1.0, 0.0); glVertex2f(1.0f, -1.0f); glTexCoord2f(0.0, 1.0); glVertex2f(-1.0f, 1.0f); glTexCoord2f(1.0, 1.0); glVertex2f(1.0f, 1.0f); glEnd(); #endif /* BROKEN */ glDeleteTextures(1, &texture); check_gl_call("draw with 2x2 texture\n"); glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, 1); glBufferData(GL_ARRAY_BUFFER, sizeof(quad), quad, GL_DYNAMIC_DRAW); check_gl_call("create buffer"); glGenSamplers(1, &sampler); glGenTextures(1, &render_target); glBindTexture(GL_TEXTURE_2D, render_target); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 640, 480, 0, GL_RGBA, GL_FLOAT, NULL); check_gl_call("create render target texture"); glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 3); glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 512, 256, 0, GL_RGBA, GL_FLOAT, NULL); glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 256, 128, 0, GL_RGBA, GL_FLOAT, NULL); glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA32F, 128, 64, 0, GL_RGBA, GL_FLOAT, NULL); glTexImage2D(GL_TEXTURE_2D, 3, GL_RGBA32F, 64, 32, 0, GL_RGBA, GL_FLOAT, NULL); glGenFramebuffers(1, &framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, render_target, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); check_gl_call("create framebuffer"); glReadBuffer(GL_ZERO); glDrawBuffer(GL_ZERO); draw_buffers = GL_COLOR_ATTACHMENT0; glDrawBuffers(1, &draw_buffers); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) fprintf(stderr, "Incomplete frambuffer!\n"); check_gl_call("framebuffer setup"); fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragment_shader, 1, &fragment_shader_source, 0); glCompileShader(fragment_shader); glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &status); if (status == GL_FALSE) fprintf(stderr, "Failed to compile fragment shader.\n"); check_gl_call("compile fragment shader"); vertex_shader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertex_shader, 1, &vertex_shader_source, 0); glCompileShader(vertex_shader); glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &status); if (status == GL_FALSE) fprintf(stderr, "Failed to compile vertex shader.\n"); check_gl_call("compile vertex shader"); program = glCreateProgram(); glAttachShader(program, vertex_shader); glAttachShader(program, fragment_shader); glLinkProgram(program); glGetProgramiv(program, GL_LINK_STATUS, &status); if (status == GL_FALSE) fprintf(stderr, "Failed to link program.\n"); check_gl_call("link program"); glClear(GL_COLOR_BUFFER_BIT); glUseProgram(program); glBindTexture(GL_TEXTURE_2D, texture); glBindSampler(0, sampler); glBindBuffer(GL_ARRAY_BUFFER, buffer); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); check_gl_call("draw"); data = malloc(640 * 480 * 4 * sizeof(float)); glBindTexture(GL_TEXTURE_2D, render_target); glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, data); printf("width: %f height %f miplevels %f\n", data[0], data[1], data[2]); free(data); glDeleteBuffers(1, &buffer); glDeleteSamplers(1, &sampler); glDeleteTextures(1, &render_target); glDeleteTextures(1, &texture); glDeleteFramebuffers(1, &framebuffer); glDeleteShader(fragment_shader); glDeleteShader(vertex_shader); glDeleteProgram(program); check_gl_call("delete resources"); } int main(int argc, char* argv[]) { SDL_Window *window; SDL_Init(SDL_INIT_VIDEO); window = SDL_CreateWindow( "OpenGL window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_OPENGL ); if (!window) { fprintf(stderr, "Could not create window: %s\n.", SDL_GetError()); return 1; } SDL_GLContext glcontext = SDL_GL_CreateContext(window); fprintf(stderr, "Renderer: %s.\n", glGetString(GL_RENDERER)); fprintf(stderr, "Version: %s.\n", glGetString(GL_VERSION)); load_gl_procs(); glClearColor(1.0f , 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); run_test(); SDL_GL_SwapWindow(window); SDL_GL_DeleteContext(glcontext); SDL_DestroyWindow(window); SDL_Quit(); return 0; }