texenvprogram: fix for ARB_draw_buffers.
[mesa.git] / progs / gallium / python / tests / texture_sample.py
1 #!/usr/bin/env python
2 ##########################################################################
3 #
4 # Copyright 2009 VMware, Inc.
5 # Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
6 # All Rights Reserved.
7 #
8 # Permission is hereby granted, free of charge, to any person obtaining a
9 # copy of this software and associated documentation files (the
10 # "Software"), to deal in the Software without restriction, including
11 # without limitation the rights to use, copy, modify, merge, publish,
12 # distribute, sub license, and/or sell copies of the Software, and to
13 # permit persons to whom the Software is furnished to do so, subject to
14 # the following conditions:
15 #
16 # The above copyright notice and this permission notice (including the
17 # next paragraph) shall be included in all copies or substantial portions
18 # of the Software.
19 #
20 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
23 # IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
24 # ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 #
28 ##########################################################################
29
30
31 from gallium import *
32 from base import *
33
34
35 def lods(*dims):
36 size = max(dims)
37 lods = 0
38 while size:
39 lods += 1
40 size >>= 1
41 return lods
42
43
44 def minify(dims, level = 1):
45 return [max(dim>>level, 1) for dim in dims]
46
47
48 def tex_coords(texture, face, level, zslice):
49 st = [
50 [0.0, 0.0],
51 [1.0, 0.0],
52 [1.0, 1.0],
53 [0.0, 1.0],
54 ]
55
56 if texture.target == PIPE_TEXTURE_2D:
57 return [[s, t, 0.0] for s, t in st]
58 elif texture.target == PIPE_TEXTURE_3D:
59 depth = texture.get_depth(level)
60 if depth > 1:
61 r = float(zslice)/float(depth - 1)
62 else:
63 r = 0.0
64 return [[s, t, r] for s, t in st]
65 elif texture.target == PIPE_TEXTURE_CUBE:
66 result = []
67 for s, t in st:
68 # See http://developer.nvidia.com/object/cube_map_ogl_tutorial.html
69 sc = 2.0*s - 1.0
70 tc = 2.0*t - 1.0
71 if face == PIPE_TEX_FACE_POS_X:
72 rx = 1.0
73 ry = -tc
74 rz = -sc
75 if face == PIPE_TEX_FACE_NEG_X:
76 rx = -1.0
77 ry = -tc
78 rz = sc
79 if face == PIPE_TEX_FACE_POS_Y:
80 rx = sc
81 ry = 1.0
82 rz = tc
83 if face == PIPE_TEX_FACE_NEG_Y:
84 rx = sc
85 ry = -1.0
86 rz = -tc
87 if face == PIPE_TEX_FACE_POS_Z:
88 rx = sc
89 ry = -tc
90 rz = 1.0
91 if face == PIPE_TEX_FACE_NEG_Z:
92 rx = -sc
93 ry = -tc
94 rz = -1.0
95 result.append([rx, ry, rz])
96 return result
97
98 def is_pot(n):
99 return n & (n - 1) == 0
100
101
102 class TextureColorSampleTest(TestCase):
103
104 tags = (
105 'target',
106 'format',
107 'width',
108 'height',
109 'depth',
110 'last_level',
111 'face',
112 'level',
113 'zslice',
114 )
115
116 def test(self):
117 dev = self.dev
118
119 target = self.target
120 format = self.format
121 width = self.width
122 height = self.height
123 depth = self.depth
124 last_level = self.last_level
125 face = self.face
126 level = self.level
127 zslice = self.zslice
128
129 tex_usage = PIPE_TEXTURE_USAGE_SAMPLER
130 geom_flags = 0
131 if width != height:
132 geom_flags |= PIPE_TEXTURE_GEOM_NON_SQUARE
133 if not is_pot(width) or not is_pot(height) or not is_pot(depth):
134 geom_flags |= PIPE_TEXTURE_GEOM_NON_POWER_OF_TWO
135
136 if not dev.is_format_supported(format, target, tex_usage, geom_flags):
137 raise TestSkip
138
139 ctx = self.dev.context_create()
140
141 # disabled blending/masking
142 blend = Blend()
143 blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE
144 blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE
145 blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO
146 blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO
147 blend.rt[0].colormask = PIPE_MASK_RGBA
148 ctx.set_blend(blend)
149
150 # no-op depth/stencil/alpha
151 depth_stencil_alpha = DepthStencilAlpha()
152 ctx.set_depth_stencil_alpha(depth_stencil_alpha)
153
154 # rasterizer
155 rasterizer = Rasterizer()
156 rasterizer.front_winding = PIPE_WINDING_CW
157 rasterizer.cull_mode = PIPE_WINDING_NONE
158 rasterizer.bypass_vs_clip_and_viewport = 1
159 ctx.set_rasterizer(rasterizer)
160
161 # samplers
162 sampler = Sampler()
163 sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE
164 sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE
165 sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE
166 sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST
167 sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST
168 sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST
169 sampler.normalized_coords = 1
170 sampler.min_lod = 0
171 sampler.max_lod = PIPE_MAX_TEXTURE_LEVELS - 1
172 ctx.set_fragment_sampler(0, sampler)
173
174 # texture
175 texture = dev.texture_create(
176 target = target,
177 format = format,
178 width = width,
179 height = height,
180 depth = depth,
181 last_level = last_level,
182 tex_usage = tex_usage,
183 )
184
185 expected_rgba = FloatArray(height*width*4)
186 texture.get_surface(
187 face = face,
188 level = level,
189 zslice = zslice,
190 ).sample_rgba(expected_rgba)
191
192 ctx.set_fragment_sampler_texture(0, texture)
193
194 # framebuffer
195 cbuf_tex = dev.texture_create(
196 PIPE_FORMAT_B8G8R8A8_UNORM,
197 width,
198 height,
199 tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET,
200 )
201
202 cbuf = cbuf_tex.get_surface()
203 fb = Framebuffer()
204 fb.width = width
205 fb.height = height
206 fb.nr_cbufs = 1
207 fb.set_cbuf(0, cbuf)
208 ctx.set_framebuffer(fb)
209 rgba = FloatArray(4);
210 rgba[0] = 0.5
211 rgba[1] = 0.5
212 rgba[2] = 0.5
213 rgba[3] = 0.5
214 ctx.clear(PIPE_CLEAR_COLOR, rgba, 0.0, 0)
215 del fb
216
217 # vertex shader
218 vs = Shader('''
219 VERT
220 DCL IN[0], POSITION, CONSTANT
221 DCL IN[1], GENERIC, CONSTANT
222 DCL OUT[0], POSITION, CONSTANT
223 DCL OUT[1], GENERIC, CONSTANT
224 0:MOV OUT[0], IN[0]
225 1:MOV OUT[1], IN[1]
226 2:END
227 ''')
228 #vs.dump()
229 ctx.set_vertex_shader(vs)
230
231 # fragment shader
232 op = {
233 PIPE_TEXTURE_1D: "1D",
234 PIPE_TEXTURE_2D: "2D",
235 PIPE_TEXTURE_3D: "3D",
236 PIPE_TEXTURE_CUBE: "CUBE",
237 }[target]
238 fs = Shader('''
239 FRAG
240 DCL IN[0], GENERIC[0], LINEAR
241 DCL OUT[0], COLOR, CONSTANT
242 DCL SAMP[0], CONSTANT
243 0:TEX OUT[0], IN[0], SAMP[0], %s
244 1:END
245 ''' % op)
246 #fs.dump()
247 ctx.set_fragment_shader(fs)
248
249 nverts = 4
250 nattrs = 2
251 verts = FloatArray(nverts * nattrs * 4)
252
253 x = 0
254 y = 0
255 w, h = minify((width, height), level)
256
257 pos = [
258 [x, y],
259 [x+w, y],
260 [x+w, y+h],
261 [x, y+h],
262 ]
263
264 tex = tex_coords(texture, face, level, zslice)
265
266 for i in range(0, 4):
267 j = 8*i
268 verts[j + 0] = pos[i][0] # x
269 verts[j + 1] = pos[i][1] # y
270 verts[j + 2] = 0.0 # z
271 verts[j + 3] = 1.0 # w
272 verts[j + 4] = tex[i][0] # s
273 verts[j + 5] = tex[i][1] # r
274 verts[j + 6] = tex[i][2] # q
275 verts[j + 7] = 1.0
276
277 ctx.draw_vertices(PIPE_PRIM_TRIANGLE_FAN,
278 nverts,
279 nattrs,
280 verts)
281
282 ctx.flush()
283
284 cbuf = cbuf_tex.get_surface()
285
286 self.assert_rgba(cbuf, x, y, w, h, expected_rgba, 4.0/256, 0.85)
287
288
289 class TextureDepthSampleTest(TestCase):
290
291 tags = (
292 'target',
293 'format',
294 'width',
295 'height',
296 'depth',
297 'last_level',
298 'face',
299 'level',
300 'zslice',
301 )
302
303 def test(self):
304 dev = self.dev
305
306 target = self.target
307 format = self.format
308 width = self.width
309 height = self.height
310 depth = self.depth
311 last_level = self.last_level
312 face = self.face
313 level = self.level
314 zslice = self.zslice
315
316 tex_usage = PIPE_TEXTURE_USAGE_SAMPLER
317 geom_flags = 0
318 if width != height:
319 geom_flags |= PIPE_TEXTURE_GEOM_NON_SQUARE
320 if not is_pot(width) or not is_pot(height) or not is_pot(depth):
321 geom_flags |= PIPE_TEXTURE_GEOM_NON_POWER_OF_TWO
322
323 if not dev.is_format_supported(format, target, tex_usage, geom_flags):
324 raise TestSkip
325
326 ctx = self.dev.context_create()
327
328 # disabled blending/masking
329 blend = Blend()
330 blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE
331 blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE
332 blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO
333 blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO
334 blend.rt[0].colormask = PIPE_MASK_RGBA
335 ctx.set_blend(blend)
336
337 # depth/stencil/alpha
338 depth_stencil_alpha = DepthStencilAlpha()
339 depth_stencil_alpha.depth.enabled = 1
340 depth_stencil_alpha.depth.writemask = 1
341 depth_stencil_alpha.depth.func = PIPE_FUNC_LESS
342 ctx.set_depth_stencil_alpha(depth_stencil_alpha)
343
344 # rasterizer
345 rasterizer = Rasterizer()
346 rasterizer.front_winding = PIPE_WINDING_CW
347 rasterizer.cull_mode = PIPE_WINDING_NONE
348 rasterizer.bypass_vs_clip_and_viewport = 1
349 ctx.set_rasterizer(rasterizer)
350
351 # samplers
352 sampler = Sampler()
353 sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE
354 sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE
355 sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE
356 sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST
357 sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST
358 sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST
359 sampler.normalized_coords = 1
360 sampler.min_lod = 0
361 sampler.max_lod = PIPE_MAX_TEXTURE_LEVELS - 1
362 ctx.set_fragment_sampler(0, sampler)
363
364 # texture
365 texture = dev.texture_create(
366 target = target,
367 format = format,
368 width = width,
369 height = height,
370 depth = depth,
371 last_level = last_level,
372 tex_usage = tex_usage,
373 )
374
375 expected_rgba = FloatArray(height*width*4)
376 texture.get_surface(
377 face = face,
378 level = level,
379 zslice = zslice,
380 ).sample_rgba(expected_rgba)
381
382 ctx.set_fragment_sampler_texture(0, texture)
383
384 # framebuffer
385 cbuf_tex = dev.texture_create(
386 PIPE_FORMAT_B8G8R8A8_UNORM,
387 width,
388 height,
389 tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET,
390 )
391
392 zsbuf_tex = dev.texture_create(
393 PIPE_FORMAT_X8Z24_UNORM,
394 width,
395 height,
396 tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET,
397 )
398
399 cbuf = cbuf_tex.get_surface()
400 zsbuf = zsbuf_tex.get_surface()
401 fb = Framebuffer()
402 fb.width = width
403 fb.height = height
404 fb.nr_cbufs = 1
405 fb.set_cbuf(0, cbuf)
406 fb.set_zsbuf(zsbuf)
407 ctx.set_framebuffer(fb)
408 rgba = FloatArray(4);
409 rgba[0] = 0.5
410 rgba[1] = 0.5
411 rgba[2] = 0.5
412 rgba[3] = 0.5
413 ctx.clear(PIPE_CLEAR_DEPTHSTENCIL, rgba, 1.0, 0)
414 del fb
415
416 # vertex shader
417 vs = Shader('''
418 VERT
419 DCL IN[0], POSITION, CONSTANT
420 DCL IN[1], GENERIC, CONSTANT
421 DCL OUT[0], POSITION, CONSTANT
422 DCL OUT[1], GENERIC, CONSTANT
423 0:MOV OUT[0], IN[0]
424 1:MOV OUT[1], IN[1]
425 2:END
426 ''')
427 #vs.dump()
428 ctx.set_vertex_shader(vs)
429
430 # fragment shader
431 op = {
432 PIPE_TEXTURE_1D: "1D",
433 PIPE_TEXTURE_2D: "2D",
434 PIPE_TEXTURE_3D: "3D",
435 PIPE_TEXTURE_CUBE: "CUBE",
436 }[target]
437 fs = Shader('''
438 FRAG
439 DCL IN[0], GENERIC[0], LINEAR
440 DCL SAMP[0], CONSTANT
441 DCL OUT[0].z, POSITION
442 0:TEX OUT[0].z, IN[0], SAMP[0], %s
443 1:END
444 ''' % op)
445 #fs.dump()
446 ctx.set_fragment_shader(fs)
447
448 nverts = 4
449 nattrs = 2
450 verts = FloatArray(nverts * nattrs * 4)
451
452 x = 0
453 y = 0
454 w, h = minify((width, height), level)
455
456 pos = [
457 [x, y],
458 [x+w, y],
459 [x+w, y+h],
460 [x, y+h],
461 ]
462
463 tex = tex_coords(texture, face, level, zslice)
464
465 for i in range(0, 4):
466 j = 8*i
467 verts[j + 0] = pos[i][0] # x
468 verts[j + 1] = pos[i][1] # y
469 verts[j + 2] = 0.0 # z
470 verts[j + 3] = 1.0 # w
471 verts[j + 4] = tex[i][0] # s
472 verts[j + 5] = tex[i][1] # r
473 verts[j + 6] = tex[i][2] # q
474 verts[j + 7] = 1.0
475
476 ctx.draw_vertices(PIPE_PRIM_TRIANGLE_FAN,
477 nverts,
478 nattrs,
479 verts)
480
481 ctx.flush()
482
483 zsbuf = zsbuf_tex.get_surface()
484
485 self.assert_rgba(zsbuf, x, y, w, h, expected_rgba, 4.0/256, 0.85)
486
487
488
489
490 def main():
491 dev = Device()
492 suite = TestSuite()
493
494 targets = [
495 PIPE_TEXTURE_2D,
496 PIPE_TEXTURE_CUBE,
497 PIPE_TEXTURE_3D,
498 ]
499
500 color_formats = [
501 PIPE_FORMAT_B8G8R8A8_UNORM,
502 PIPE_FORMAT_B8G8R8X8_UNORM,
503 #PIPE_FORMAT_B8G8R8A8_SRGB,
504 PIPE_FORMAT_B5G6R5_UNORM,
505 PIPE_FORMAT_B5G5R5A1_UNORM,
506 PIPE_FORMAT_B4G4R4A4_UNORM,
507 PIPE_FORMAT_A8_UNORM,
508 PIPE_FORMAT_L8_UNORM,
509 PIPE_FORMAT_UYVY,
510 PIPE_FORMAT_DXT1_RGB,
511 #PIPE_FORMAT_DXT1_RGBA,
512 #PIPE_FORMAT_DXT3_RGBA,
513 #PIPE_FORMAT_DXT5_RGBA,
514 ]
515
516 depth_formats = [
517 PIPE_FORMAT_Z32_UNORM,
518 PIPE_FORMAT_S8Z24_UNORM,
519 PIPE_FORMAT_X8Z24_UNORM,
520 PIPE_FORMAT_Z16_UNORM,
521 ]
522
523 sizes = [64, 32, 16, 8, 4, 2, 1]
524 #sizes = [1020, 508, 252, 62, 30, 14, 6, 3]
525 #sizes = [64]
526 #sizes = [63]
527
528 faces = [
529 PIPE_TEX_FACE_POS_X,
530 PIPE_TEX_FACE_NEG_X,
531 PIPE_TEX_FACE_POS_Y,
532 PIPE_TEX_FACE_NEG_Y,
533 PIPE_TEX_FACE_POS_Z,
534 PIPE_TEX_FACE_NEG_Z,
535 ]
536
537 for format in color_formats:
538 for target in targets:
539 for size in sizes:
540 if target == PIPE_TEXTURE_3D:
541 depth = size
542 else:
543 depth = 1
544 for face in faces:
545 if target != PIPE_TEXTURE_CUBE and face:
546 continue
547 levels = lods(size)
548 for last_level in range(levels):
549 for level in range(0, last_level + 1):
550 zslice = 0
551 while zslice < depth >> level:
552 test = TextureColorSampleTest(
553 dev = dev,
554 target = target,
555 format = format,
556 width = size,
557 height = size,
558 depth = depth,
559 last_level = last_level,
560 face = face,
561 level = level,
562 zslice = zslice,
563 )
564 suite.add_test(test)
565 zslice = (zslice + 1)*2 - 1
566 for format in depth_formats:
567 target = PIPE_TEXTURE_2D
568 depth = 1
569 face = 0
570 last_level = 0
571 level = 0
572 zslice = 0
573 for size in sizes:
574 test = TextureDepthSampleTest(
575 dev = dev,
576 target = target,
577 format = format,
578 width = size,
579 height = size,
580 depth = depth,
581 last_level = last_level,
582 face = face,
583 level = level,
584 zslice = zslice,
585 )
586 suite.add_test(test)
587 suite.run()
588
589
590 if __name__ == '__main__':
591 main()