2 * Copyright © 2013 Chris Forbes
3 * Copyright 2014 Intel Corporation
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
25 /** @file texture-storage-multisample.c
27 * Based on arb_texture_storage_multisample/tex-storage.c by Chris Forbes and
28 * piglit_multisample_texture in piglit_util_gl.c by Jason Ekstrand.
29 * Adapted to test glTextureStorage2DMultisample and
30 * glTextureStorage3DMultisample by Laura Ekstrand (laura@jlekstrand.net).
33 #include "piglit-util-gl.h"
35 PIGLIT_GL_TEST_CONFIG_BEGIN
37 config
.supports_gl_core_version
= 31;
39 config
.window_visual
= PIGLIT_GL_VISUAL_RGBA
|
40 PIGLIT_GL_VISUAL_DOUBLE
;
41 config
.khr_no_error_support
= PIGLIT_NO_ERRORS
;
43 PIGLIT_GL_TEST_CONFIG_END
45 /* This has the modelview matrix built in. */
46 static const char multisample_texture_vs_source
[] =
48 "in vec2 piglit_vertex;\n"
49 "out vec2 tex_coords;\n"
52 " tex_coords = piglit_vertex;\n"
53 " vec2 pos = (piglit_vertex.xy * 2) - vec2(1, 1);\n"
54 " gl_Position = vec4(pos, 0, 1);\n"
58 static const char multisample_texture_fs_source
[] =
60 "#extension GL_ARB_sample_shading : enable\n"
61 "in vec2 tex_coords;\n"
62 "uniform sampler2DArray tex;\n"
63 "uniform int tex_depth;\n"
67 " int layer = (gl_SampleID * tex_depth) + z;\n"
68 " gl_FragColor = texture(tex, vec3(tex_coords, layer));\n"
73 * Uploads an arbitrary multisample texture.
74 * TODO: Make this part of Mesa meta?
76 * This function acts like glTexSub*Image for multisample textures.
77 * For the texture given, it assumes that glTexImage[23]DMultisample or
78 * glTex*Storage[23]DMultisample has already been called to establish the
81 * When this function returns, multisample texture will be bound to the
82 * currently active texture.
84 * \param tex Texture name for a previously initialized texture.
85 * \param target either GL_TEXTURE_2D_MULTISAMPLE or
86 * GL_TEXTURE2D_MULTISAMPLE_ARRAY
87 * \param internalformat a renderable color format accepted by
88 * glTexImage2DMultisample
89 * \param width texture width
90 * \param height texture height
91 * \param depth texture depth. If target is
92 * GL_TEXTURE_2D_MULTISAMPLE, this must be 1.
93 * \param samples the number of samples
94 * \param format format of the pixel data
95 * \param type type of the pixel data
96 * \param data pixel data with which to fill the texture
97 * You need data for each sample. The samples should be
102 texture_sub_image_multisample(GLenum tex
, GLenum target
,
103 GLenum internalFormat
, unsigned width
,
104 unsigned height
, unsigned depth
,
105 unsigned samples
, GLenum format
, GLenum type
,
108 static GLuint prog
= 0;
109 static GLint tex_loc
, tex_depth_loc
, z_loc
;
110 static GLuint fbo
, array_tex
;
118 GLboolean arb_sample_shading
;
119 GLfloat min_sample_shading
;
120 GLint clamp_fragment_color
;
123 piglit_require_extension("GL_ARB_texture_multisample");
124 piglit_require_extension("GL_ARB_sample_shading");
126 if (target
== GL_TEXTURE_2D_MULTISAMPLE
) {
128 } else if (target
== GL_TEXTURE_2D_MULTISAMPLE_ARRAY
) {
131 assert(!"Invalid texture target");
136 /* First-run setup */
137 prog
= piglit_build_simple_program(
138 multisample_texture_vs_source
,
139 multisample_texture_fs_source
);
141 tex_loc
= glGetUniformLocation(prog
, "tex");
142 tex_depth_loc
= glGetUniformLocation(prog
, "tex_depth");
143 z_loc
= glGetUniformLocation(prog
, "z");
145 glGenFramebuffers(1, &fbo
);
146 glGenTextures(1, &array_tex
);
149 /* Backup client values so we can restore them later */
150 glGetIntegerv(GL_ACTIVE_TEXTURE
, &backup
.active_tex
);
151 glGetIntegerv(GL_CURRENT_PROGRAM
, &backup
.prog
);
152 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING
, &backup
.draw_fbo
);
153 glGetIntegerv(GL_VIEWPORT
, backup
.viewport
);
154 glGetBooleanv(GL_SAMPLE_SHADING_ARB
, &backup
.arb_sample_shading
);
155 glGetFloatv(GL_MIN_SAMPLE_SHADING_VALUE_ARB
, &backup
.min_sample_shading
);
157 /* This ensures that copying is done on a per-sample basis rather than
158 * the default per-pixel basis.
160 glEnable(GL_SAMPLE_SHADING_ARB
);
161 glMinSampleShadingARB(1.0f
);
163 /* Load the data into a texture for drawing. */
164 glBindTexture(GL_TEXTURE_2D_ARRAY
, array_tex
);
165 glTexParameteri(GL_TEXTURE_2D_ARRAY
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
166 glTexParameteri(GL_TEXTURE_2D_ARRAY
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
167 glTexImage3D(GL_TEXTURE_2D_ARRAY
, 0, internalFormat
, width
, height
,
168 depth
* samples
, 0, format
, type
, data
);
170 /* Bind the special FBO and attach our texture to it. */
171 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, fbo
);
172 glViewport(0, 0, width
, height
);
175 glUniform1i(tex_loc
, backup
.active_tex
- GL_TEXTURE0
);
176 glUniform1i(tex_depth_loc
, depth
);
179 /* When we call draw arrays, the data (in array_tex) will get drawn
180 * into our texture (in tex) because it's attached to
183 if (target
== GL_TEXTURE_2D_MULTISAMPLE
) {
184 glUniform1i(z_loc
, 0);
185 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER
,
186 GL_COLOR_ATTACHMENT0
,
188 if (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER
) !=
189 GL_FRAMEBUFFER_COMPLETE
)
192 piglit_draw_rect(0.0, 0.0, 2.0, 2.0);
194 for (z
= 0; z
< depth
; ++z
) {
195 glUniform1i(z_loc
, z
);
196 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER
,
197 GL_COLOR_ATTACHMENT0
,
199 if (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER
) !=
200 GL_FRAMEBUFFER_COMPLETE
)
203 piglit_draw_rect(0.0, 0.0, 2.0, 2.0);
207 /* Restore values for the client */
208 if (!backup
.arb_sample_shading
)
209 glDisable(GL_SAMPLE_SHADING_ARB
);
210 glMinSampleShadingARB(backup
.min_sample_shading
);
212 glUseProgram(backup
.prog
);
213 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, backup
.draw_fbo
);
214 glViewport(backup
.viewport
[0], backup
.viewport
[1],
215 backup
.viewport
[2], backup
.viewport
[3]);
216 glBindTexture(target
, tex
);
220 check_non_generated_texture(void)
224 /* Section 8.19 of the OpenGL 4.5 Core Profile spec says:
226 * "An INVALID_OPERATION error is generated by TextureStorage* if
227 * texture is not the name of an existing texture object."
229 glTextureStorage2DMultisample(250, 4, GL_RGBA8
, 64, 64, GL_TRUE
);
230 pass
= piglit_check_gl_error(GL_INVALID_OPERATION
) && pass
;
231 glTextureStorage3DMultisample(250, 4, GL_RGBA8
, 64, 64, 3, GL_TRUE
);
232 pass
= piglit_check_gl_error(GL_INVALID_OPERATION
) && pass
;
234 piglit_report_subtest_result(pass
? PIGLIT_PASS
: PIGLIT_FAIL
,
235 "non-generated texture name");
240 check_unsized_format(void)
244 /* Section 8.19 of the OpenGL 4.5 Core Profile spec says:
246 * "An INVALID_ENUM error is generated if internalformat is one of
247 * the unsized base internal formats listed in table 8.11."
250 glCreateTextures(GL_TEXTURE_2D_MULTISAMPLE
, 1, &tex
);
251 glTextureStorage2DMultisample(tex
, 4, GL_RGBA
, 64, 64, GL_TRUE
);
253 /* unsized formats may not be used with TexStorage* */
254 pass
= piglit_check_gl_error(GL_INVALID_ENUM
) && pass
;
255 piglit_report_subtest_result(pass
? PIGLIT_PASS
: PIGLIT_FAIL
,
261 check_immutable(void)
268 glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES
, &samples
);
270 glCreateTextures(GL_TEXTURE_2D_MULTISAMPLE
, 1, &tex
);
271 /* specify storage for the texture, and mark it immutable-format */
272 glTextureStorage2DMultisample(tex
, samples
, GL_RGBA8
, 64, 64, GL_TRUE
);
273 pass
= piglit_check_gl_error(GL_NO_ERROR
) && pass
;
275 /* should now have TEXTURE_IMMUTABLE_FORMAT */
276 glGetTextureParameteriv(tex
, GL_TEXTURE_IMMUTABLE_FORMAT
, ¶m
);
278 if (!piglit_check_gl_error(GL_NO_ERROR
)) {
280 printf("failed to fetch texture parameter"
281 " TEXTURE_IMMUTABLE_FORMAT\n");
284 if (param
!= GL_TRUE
) {
286 printf("expected TEXTURE_IMMUTABLE_FORMAT to be true,"
290 /* calling Tex*Storage* again on the same texture should fail */
291 glTextureStorage2DMultisample(tex
, samples
, GL_RGBA8
, 32, 32, GL_TRUE
);
292 if (!piglit_check_gl_error(GL_INVALID_OPERATION
)) {
294 printf("expected respecifying an immutable-format texture"
295 " (with TexStorage*Multisample) to fail\n");
298 /* calling TexImage2DMultisample should fail too */
299 glBindTextureUnit(0, tex
);
300 glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE
,
301 samples
, GL_RGBA8
, 32, 32, GL_TRUE
);
303 if (!piglit_check_gl_error(GL_INVALID_OPERATION
)) {
305 printf("expected respecifying an immutable-format texture"
306 " (with TexImage*Multisample) to fail\n");
309 piglit_report_subtest_result(pass
? PIGLIT_PASS
: PIGLIT_FAIL
,
315 draw_multisampled(void)
323 /* Make a texture of size piglit_width x piglit_height that is divided
324 * into two triangles by a diagonal (\) line. (Use \ rather than /
325 * because texture_sub_image_multisample uses /.)
327 /* TODO: Do spatial anti-aliasing rather than blending. */
328 GLubyte
* data
= malloc(4 * samples
* piglit_width
* piglit_height
*
330 float m
= ((float) piglit_height
/ piglit_width
);
331 for (z
= 0; z
< samples
; ++z
) {
332 for (y
= 0; y
< piglit_height
; ++y
) {
333 for (x
= 0; x
< piglit_width
; ++x
) {
334 idx
= 4 * ((z
* piglit_height
+ y
) *
336 sample_mult
= ((float) z
)/samples
;
337 if (y
<= ((int) piglit_height
- (m
* x
))) {
338 /* Green below or on the line. */
339 data
[idx
+ 0] = 0 * sample_mult
;
340 data
[idx
+ 1] = 255 * sample_mult
;
341 data
[idx
+ 2] = 0 * sample_mult
;
344 /* White above the line. */
345 data
[idx
+ 0] = 255 * sample_mult
;
346 data
[idx
+ 1] = 255 * sample_mult
;
347 data
[idx
+ 2] = 255 * sample_mult
;
354 /* Set up the image. */
355 glCreateTextures(GL_TEXTURE_2D_MULTISAMPLE
, 1, &texture
);
356 glTextureStorage2DMultisample(texture
, samples
, GL_RGBA8
,
357 piglit_width
, piglit_height
, GL_FALSE
);
358 texture_sub_image_multisample(texture
, GL_TEXTURE_2D_MULTISAMPLE
,
359 GL_RGBA8
, piglit_width
, piglit_height
,
360 1, samples
, GL_RGBA
, GL_UNSIGNED_BYTE
,
363 /* Draw the image. Can't use piglit_draw_rect_tex because the OpenGL
364 * 1.0 pipeline doesn't handle multisample textures.
366 glGenFramebuffers(1, &fbo
);
367 glBindFramebuffer(GL_READ_FRAMEBUFFER
, fbo
);
368 glFramebufferTexture2D(GL_READ_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
369 GL_TEXTURE_2D_MULTISAMPLE
, texture
, 0);
370 glBlitFramebuffer(0, 0, piglit_width
, piglit_height
,
371 0, 0, piglit_width
, piglit_height
,
372 GL_COLOR_BUFFER_BIT
, GL_LINEAR
);
373 pass
= piglit_check_gl_error(GL_NO_ERROR
) && pass
;
375 /* TODO: Add a Piglit probe call to check the output */
376 if (!piglit_automatic
) {
377 piglit_present_results();
380 piglit_report_subtest_result(pass
? PIGLIT_PASS
: PIGLIT_FAIL
,
381 "multisampled drawing");
389 trivial_but_should_work(void)
395 glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES
, &samples
);
398 glCreateTextures(GL_TEXTURE_2D_MULTISAMPLE
, 1, &texture
);
399 glTextureStorage2DMultisample(texture
, samples
, GL_RGBA8
, 64, 64, GL_TRUE
);
400 pass
= piglit_check_gl_error(GL_NO_ERROR
) && pass
;
403 glDeleteTextures(1, &texture
);
404 glCreateTextures(GL_TEXTURE_2D_MULTISAMPLE_ARRAY
, 1, &texture
);
405 glTextureStorage3DMultisample(texture
, samples
, GL_RGBA8
, 64, 64, 3,
407 pass
= piglit_check_gl_error(GL_NO_ERROR
) && pass
;
409 piglit_report_subtest_result(pass
? PIGLIT_PASS
: PIGLIT_FAIL
,
410 "trivial, but should work");
415 check_improper_effective_target(void)
420 /* 3D case with 2D target */
421 glCreateTextures(GL_TEXTURE_2D_MULTISAMPLE
, 1, &texture
);
422 glTextureStorage3DMultisample(texture
, 4, GL_RGBA8
, 64, 64, 3,
424 pass
= piglit_check_gl_error(GL_INVALID_OPERATION
) && pass
;
426 /* 2D case with 3D target */
427 glDeleteTextures(1, &texture
);
428 glCreateTextures(GL_TEXTURE_2D_MULTISAMPLE_ARRAY
, 1, &texture
);
429 glTextureStorage2DMultisample(texture
, 4, GL_RGBA8
, 64, 64, GL_TRUE
);
430 pass
= piglit_check_gl_error(GL_INVALID_OPERATION
) && pass
;
432 /* 2D case with non-multisampled target */
433 glDeleteTextures(1, &texture
);
434 glCreateTextures(GL_TEXTURE_2D
, 1, &texture
);
435 glTextureStorage2DMultisample(texture
, 4, GL_RGBA8
, 64, 64, GL_TRUE
);
436 pass
= piglit_check_gl_error(GL_INVALID_OPERATION
) && pass
;
438 piglit_report_subtest_result(pass
? PIGLIT_PASS
: PIGLIT_FAIL
,
439 "improper effective target");
444 piglit_init(int argc
, char **argv
)
447 piglit_require_extension("GL_ARB_direct_state_access");
448 piglit_require_extension("GL_ARB_texture_storage_multisample");
449 glGetIntegerv(GL_MAX_SAMPLES
, &max_samples
);
450 printf("Max samples = %d\n", max_samples
);
458 if (!piglit_khr_no_error
) {
459 pass
= check_non_generated_texture() && pass
;
460 pass
= check_immutable() && pass
;
461 pass
= check_unsized_format() && pass
;
462 pass
= check_improper_effective_target() && pass
;
465 pass
= trivial_but_should_work() && pass
;
466 pass
= draw_multisampled() && pass
;
468 return pass
? PIGLIT_PASS
: PIGLIT_FAIL
;