2 * Copyright © 2016 VMware, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 * Neha Bhende <bhenden@vmware.com>
30 * To test a bug in glClear() with GL_FRAMEBUFFER_SRGB enabled on nVidia GPUs.
31 * nVidia GPUs seems to disable GL_FRAMEBUFFER_SRGB after using a PBO to
32 * define a GL_BGRA4 texture.
33 * This test creates fbo and the clear it with GL_FRAMEBUFFER_SRGB.
34 * Before reading fbo pixels, test performs some PBO operations and creates
35 * GL_RGBA4 texture. So when we readback fbo pixels, it has GL_FRAMEBUFFER_SRGB
37 * For example, we clear the framebuffer with (R, G, B, A)=(0, 0, 127, 0)
38 * with GL_FRAMEBUFFER_SRGB enabled, we should get (0, 0, 187, 0) but we get
45 #include "piglit-util-gl.h"
48 PIGLIT_GL_TEST_CONFIG_BEGIN
49 config
.supports_gl_compat_version
= 13;
50 config
.window_visual
= PIGLIT_GL_VISUAL_RGB
;
51 PIGLIT_GL_TEST_CONFIG_END
53 const unsigned int texWidth
= 256;
54 const unsigned int texHeight
= 256;
55 const unsigned int level
= 0;
56 const unsigned int numLevels
= 1;
57 const GLenum texFormat
= GL_BGRA
;
58 const GLenum texInternalFormat
= GL_SRGB8_ALPHA8
;
59 const GLenum texType
= GL_UNSIGNED_INT_8_8_8_8_REV
;
79 createTexture2D(const GLenum internalFormat
, unsigned int numMipmapLevels
,
80 unsigned int width
, unsigned int height
)
84 glGenTextures(1, &tex
);
85 glBindTexture(GL_TEXTURE_2D
, tex
);
87 glTexStorage2D(GL_TEXTURE_2D
, numMipmapLevels
, internalFormat
,
89 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
90 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
91 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
92 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
93 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_BASE_LEVEL
, 0);
99 test2dTexelAt(const GLuint tex2D
, unsigned int mipLevel
, unsigned int x
,
100 unsigned int y
, struct BGRA8 expected
, unsigned int width
,
103 struct BGRA8
*texData
= (struct BGRA8
*)
104 malloc(width
* height
*sizeof(struct BGRA8
));
105 enum piglit_result status
= PIGLIT_PASS
;
107 glBindTexture(GL_TEXTURE_2D
, tex2D
);
108 glPixelStorei(GL_PACK_ROW_LENGTH
, width
);
109 glPixelStorei(GL_PACK_IMAGE_HEIGHT
, height
);
110 glPixelStorei(GL_PACK_ALIGNMENT
, 1);
112 glGetTexImage(GL_TEXTURE_2D
, mipLevel
, texFormat
, texType
, texData
);
114 const unsigned int offset
= y
* width
+ x
;
115 struct BGRA8 pixel
= texData
[offset
];
117 if (memcmp(&expected
, &pixel
, sizeof(struct BGRA8
))) {
118 status
= PIGLIT_FAIL
;
119 fprintf(stdout
," texel mismatch at position (%u, %u): \n", x
,y
);
120 fprintf(stdout
, "expected {%u, %u, %u, %u},"
121 " found {%u, %u, %u, %u}\n",
122 expected
.red
, expected
.green
,
123 expected
.blue
, expected
.alpha
,
124 pixel
.red
, pixel
.green
, pixel
.blue
, pixel
.alpha
);
132 /** Borrowed from Mesa */
134 linear_to_srgb(float cl
)
138 else if (cl
< 0.0031308f
)
141 return 1.055f
* powf(cl
, 0.41666f
) - 0.055f
;
156 piglit_init(int argc
, char **argv
)
158 piglit_require_extension("GL_ARB_texture_storage");
159 piglit_require_extension("GL_ARB_framebuffer_object");
160 piglit_require_extension("GL_ARB_pixel_buffer_object");
161 piglit_require_extension("GL_ARB_framebuffer_sRGB");
163 GLuint tex2D
= createTexture2D(texInternalFormat
, numLevels
,
164 texWidth
, texHeight
);
165 const struct BGRA8 clearVal
= { 127, 63, 192, 0 };
166 struct BGRA8 sRGBVal
;
168 /* compute expected sRGB value */
169 sRGBVal
.red
= (unsigned) (255 * linear_to_srgb(clearVal
.red
/ 255.0));
170 sRGBVal
.green
= (unsigned) (255 * linear_to_srgb(clearVal
.green
/ 255.0));
171 sRGBVal
.blue
= (unsigned) (255 * linear_to_srgb(clearVal
.blue
/ 255.0));
174 const unsigned int numPixels
= texWidth
* texHeight
;
176 enum piglit_result status
= PIGLIT_PASS
;
179 glGenFramebuffers(1, &fbo
);
180 glBindFramebuffer(GL_FRAMEBUFFER
, fbo
);
182 /* using 2D texture as frame buffer texture */
183 glFramebufferTexture2D(GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
184 GL_TEXTURE_2D
, tex2D
, level
);
185 if (glCheckFramebufferStatus(GL_FRAMEBUFFER
) !=
186 GL_FRAMEBUFFER_COMPLETE
) {
187 fprintf(stdout
, "Error: Cannot attach tex2D to FBO!\n");
188 piglit_report_result(PIGLIT_FAIL
);
191 glDrawBuffer(GL_COLOR_ATTACHMENT0
);
192 if (glCheckFramebufferStatus(GL_FRAMEBUFFER
) !=
193 GL_FRAMEBUFFER_COMPLETE
) {
194 fprintf(stderr
, "Error: Cannot set Draw Buffer!\n");
195 piglit_report_result(PIGLIT_FAIL
);
198 /* clearing texture tex2D with GL_FRAMEBUFFER_SRGB */
199 glViewport(0, 0, texWidth
, texHeight
);
200 glEnable(GL_FRAMEBUFFER_SRGB
);
201 glClearColor(clearVal
.red
/ 255.0f
, clearVal
.green
/ 255.0f
,
202 clearVal
.blue
/ 255.0f
, clearVal
.alpha
/ 255.0f
);
203 glClear(GL_COLOR_BUFFER_BIT
);
205 /* following code basically triggers the issue.
206 * We have sRGB fbo. PBO operations are done and GL_RGBA4
207 * texture is created, before readback.
208 * When we readback framebuffer pixels, it doesn't have expected
213 tex
= createTexture2D(GL_RGBA4
, 1, texWidth
, texHeight
);
215 /* Create a PBO and initialize it to zeros */
217 const unsigned int texDataLength
= numPixels
* sizeof(struct BGRA4
);
219 glGenBuffers(1, &unpackPbo
);
220 glBindBuffer(GL_COPY_READ_BUFFER
, unpackPbo
);
221 glBufferData(GL_COPY_READ_BUFFER
, texDataLength
, 0, GL_STREAM_DRAW
);
223 glMapBufferRange(GL_COPY_READ_BUFFER
, 0, texDataLength
,
227 fprintf(stderr
, "Error: Failed to map PBO!\n");
228 piglit_report_result(PIGLIT_FAIL
);
230 memset(ptr
, 0, texDataLength
);
231 glUnmapBuffer(GL_COPY_READ_BUFFER
);
233 glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, unpackPbo
);
235 glBindTexture(GL_TEXTURE_2D
, tex
);
236 glPixelStorei(GL_UNPACK_ROW_LENGTH
, texWidth
);
237 glPixelStorei(GL_UNPACK_IMAGE_HEIGHT
, texHeight
);
238 glPixelStorei(GL_UNPACK_ALIGNMENT
, 1);
240 glTexSubImage2D(GL_TEXTURE_2D
, level
,
243 GL_BGRA
, GL_UNSIGNED_SHORT_4_4_4_4_REV
,
246 /* now recheck 2D texture tex2D data */
247 status
= test2dTexelAt(tex2D
, level
, 0, 0, sRGBVal
,
248 texWidth
, texHeight
);
250 piglit_report_result(status
);