gallium: remove some debug assertions in vertex format validation
[mesa.git] / src / mesa / state_tracker / st_gen_mipmap.c
1 /**************************************************************************
2 *
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28
29 #include "main/imports.h"
30 #include "main/mipmap.h"
31 #include "main/teximage.h"
32 #include "main/texformat.h"
33
34 #include "shader/prog_instruction.h"
35
36 #include "pipe/p_context.h"
37 #include "pipe/p_defines.h"
38 #include "pipe/p_inlines.h"
39 #include "pipe/p_winsys.h"
40 #include "pipe/cso_cache/cso_cache.h"
41
42 #include "st_context.h"
43 #include "st_draw.h"
44 #include "st_gen_mipmap.h"
45 #include "st_program.h"
46 #include "st_cb_drawpixels.h"
47 #include "st_cb_texture.h"
48
49
50
51 static struct st_fragment_program *
52 make_tex_fragment_program(GLcontext *ctx)
53 {
54 struct st_fragment_program *stfp;
55 struct gl_program *p;
56 GLuint ic = 0;
57
58 p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
59 if (!p)
60 return NULL;
61
62 p->NumInstructions = 2;
63
64 p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
65 if (!p->Instructions) {
66 ctx->Driver.DeleteProgram(ctx, p);
67 return NULL;
68 }
69 _mesa_init_instructions(p->Instructions, p->NumInstructions);
70
71 /* TEX result.color, fragment.texcoord[0], texture[0], 2D; */
72 p->Instructions[ic].Opcode = OPCODE_TEX;
73 p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
74 p->Instructions[ic].DstReg.Index = FRAG_RESULT_COLR;
75 p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
76 p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
77 p->Instructions[ic].TexSrcUnit = 0;
78 p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX;
79 ic++;
80
81 /* END; */
82 p->Instructions[ic++].Opcode = OPCODE_END;
83
84 assert(ic == p->NumInstructions);
85
86 p->InputsRead = FRAG_BIT_TEX0;
87 p->OutputsWritten = (1 << FRAG_RESULT_COLR);
88
89 stfp = (struct st_fragment_program *) p;
90
91 st_translate_fragment_program(ctx->st, stfp, NULL,
92 stfp->tokens, ST_MAX_SHADER_TOKENS);
93
94 return stfp;
95 }
96
97
98
99
100 /**
101 * one-time init for generate mipmap
102 * XXX Note: there may be other times we need no-op/simple state like this.
103 * In that case, some code refactoring would be good.
104 */
105 void
106 st_init_generate_mipmap(struct st_context *st)
107 {
108 struct pipe_context *pipe = st->pipe;
109 struct pipe_blend_state blend;
110 struct pipe_rasterizer_state rasterizer;
111 struct pipe_depth_stencil_alpha_state depthstencil;
112
113 memset(&blend, 0, sizeof(blend));
114 blend.colormask = PIPE_MASK_RGBA;
115 st->gen_mipmap.blend_cso = pipe->create_blend_state(pipe, &blend);
116
117 memset(&depthstencil, 0, sizeof(depthstencil));
118 st->gen_mipmap.depthstencil_cso = pipe->create_depth_stencil_alpha_state(pipe, &depthstencil);
119
120 memset(&rasterizer, 0, sizeof(rasterizer));
121 st->gen_mipmap.rasterizer_cso = pipe->create_rasterizer_state(pipe, &rasterizer);
122
123 st->gen_mipmap.stfp = make_tex_fragment_program(st->ctx);
124 st->gen_mipmap.stvp = st_make_passthrough_vertex_shader(st, GL_FALSE);
125 }
126
127
128 void
129 st_destroy_generate_mipmpap(struct st_context *st)
130 {
131 struct pipe_context *pipe = st->pipe;
132
133 pipe->delete_blend_state(pipe, st->gen_mipmap.blend_cso);
134 pipe->delete_depth_stencil_alpha_state(pipe, st->gen_mipmap.depthstencil_cso);
135 pipe->delete_rasterizer_state(pipe, st->gen_mipmap.rasterizer_cso);
136
137 /* XXX free stfp, stvp */
138 }
139
140
141 static void
142 simple_viewport(struct pipe_context *pipe, uint width, uint height)
143 {
144 struct pipe_viewport_state vp;
145
146 vp.scale[0] = 0.5 * width;
147 vp.scale[1] = -0.5 * height;
148 vp.scale[2] = 1.0;
149 vp.scale[3] = 1.0;
150 vp.translate[0] = 0.5 * width;
151 vp.translate[1] = 0.5 * height;
152 vp.translate[2] = 0.0;
153 vp.translate[3] = 0.0;
154
155 pipe->set_viewport_state(pipe, &vp);
156 }
157
158
159
160 /*
161 * Draw simple [-1,1]x[-1,1] quad
162 */
163 static void
164 draw_quad(GLcontext *ctx)
165 {
166 GLfloat verts[4][2][4]; /* four verts, two attribs, XYZW */
167 GLuint i;
168 GLfloat sLeft = 0.0, sRight = 1.0;
169 GLfloat tTop = 1.0, tBot = 0.0;
170 GLfloat x0 = -1.0, x1 = 1.0;
171 GLfloat y0 = -1.0, y1 = 1.0;
172
173 /* upper-left */
174 verts[0][0][0] = x0; /* attr[0].x */
175 verts[0][0][1] = y0; /* attr[0].y */
176 verts[0][1][0] = sLeft; /* attr[1].s */
177 verts[0][1][1] = tTop; /* attr[1].t */
178
179 /* upper-right */
180 verts[1][0][0] = x1;
181 verts[1][0][1] = y0;
182 verts[1][1][0] = sRight;
183 verts[1][1][1] = tTop;
184
185 /* lower-right */
186 verts[2][0][0] = x1;
187 verts[2][0][1] = y1;
188 verts[2][1][0] = sRight;
189 verts[2][1][1] = tBot;
190
191 /* lower-left */
192 verts[3][0][0] = x0;
193 verts[3][0][1] = y1;
194 verts[3][1][0] = sLeft;
195 verts[3][1][1] = tBot;
196
197 /* same for all verts: */
198 for (i = 0; i < 4; i++) {
199 verts[i][0][2] = 0.0; /*Z*/
200 verts[i][0][3] = 1.0; /*W*/
201 verts[i][1][2] = 0.0; /*R*/
202 verts[i][1][3] = 1.0; /*Q*/
203 }
204
205 st_draw_vertices(ctx, PIPE_PRIM_QUADS, 4, (float *) verts, 2, GL_TRUE);
206 }
207
208
209
210 /**
211 * Generate mipmap levels using hardware rendering.
212 * \return TRUE if successful, FALSE if not possible
213 */
214 static boolean
215 st_render_mipmap(struct st_context *st,
216 GLenum target,
217 struct pipe_texture *pt,
218 uint baseLevel, uint lastLevel)
219 {
220 struct pipe_context *pipe = st->pipe;
221 struct pipe_framebuffer_state fb;
222 struct pipe_sampler_state sampler;
223 void *sampler_cso;
224 const uint face = _mesa_tex_target_to_face(target), zslice = 0;
225 /*const uint first_level_save = pt->first_level;*/
226 uint dstLevel;
227
228 assert(target != GL_TEXTURE_3D); /* not done yet */
229
230 /* check if we can render in the texture's format */
231 if (!pipe->is_format_supported(pipe, pt->format, PIPE_SURFACE)) {
232 return FALSE;
233 }
234
235 /* init framebuffer state */
236 memset(&fb, 0, sizeof(fb));
237 fb.num_cbufs = 1;
238
239 /* sampler state */
240 memset(&sampler, 0, sizeof(sampler));
241 sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
242 sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
243 sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
244 sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
245 sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR;
246 sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
247 sampler.normalized_coords = 1;
248
249
250 /* bind CSOs */
251 pipe->bind_blend_state(pipe, st->gen_mipmap.blend_cso);
252 pipe->bind_depth_stencil_alpha_state(pipe, st->gen_mipmap.depthstencil_cso);
253 pipe->bind_rasterizer_state(pipe, st->gen_mipmap.rasterizer_cso);
254
255 /* bind shaders */
256 pipe->bind_fs_state(pipe, st->gen_mipmap.stfp->cso->data);
257 pipe->bind_vs_state(pipe, st->gen_mipmap.stvp->cso->data);
258
259 /*
260 * XXX for small mipmap levels, it may be faster to use the software
261 * fallback path...
262 */
263 for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
264 const uint srcLevel = dstLevel - 1;
265
266 /*
267 * Setup framebuffer / dest surface
268 */
269 fb.cbufs[0] = pipe->get_tex_surface(pipe, pt, face, dstLevel, zslice);
270 pipe->set_framebuffer_state(pipe, &fb);
271
272 /*
273 * Setup sampler state
274 */
275 sampler.min_lod = sampler.max_lod = srcLevel;
276 sampler_cso = pipe->create_sampler_state(pipe, &sampler);
277 pipe->bind_sampler_state(pipe, 0, sampler_cso);
278
279 simple_viewport(pipe, pt->width[dstLevel], pt->height[dstLevel]);
280
281 /*
282 * Setup src texture, override pt->first_level so we sample from
283 * the right mipmap level.
284 */
285 /*pt->first_level = srcLevel;*/
286 pipe->set_sampler_texture(pipe, 0, pt);
287
288 draw_quad(st->ctx);
289
290 pipe->delete_sampler_state(pipe, sampler_cso);
291 }
292
293 /* restore first_level */
294 /*pt->first_level = first_level_save;*/
295
296 /* restore pipe state */
297 if (st->state.rasterizer)
298 pipe->bind_rasterizer_state(pipe, st->state.rasterizer->data);
299 if (st->state.fs)
300 pipe->bind_fs_state(pipe, st->state.fs->data);
301 if (st->state.vs)
302 pipe->bind_vs_state(pipe, st->state.vs->cso->data);
303 if (st->state.sampler[0])
304 pipe->bind_sampler_state(pipe, 0, st->state.sampler[0]->data);
305 pipe->set_sampler_texture(pipe, 0, st->state.sampler_texture[0]);
306 pipe->set_viewport_state(pipe, &st->state.viewport);
307
308 return TRUE;
309 }
310
311
312 static void
313 fallback_generate_mipmap(GLcontext *ctx, GLenum target,
314 struct gl_texture_object *texObj)
315 {
316 struct pipe_context *pipe = ctx->st->pipe;
317 struct pipe_winsys *ws = pipe->winsys;
318 struct pipe_texture *pt = st_get_texobj_texture(texObj);
319 const uint baseLevel = texObj->BaseLevel;
320 const uint lastLevel = pt->last_level;
321 const uint face = _mesa_tex_target_to_face(target), zslice = 0;
322 uint dstLevel;
323 GLenum datatype;
324 GLuint comps;
325
326 assert(target != GL_TEXTURE_3D); /* not done yet */
327
328 _mesa_format_to_type_and_comps(texObj->Image[face][baseLevel]->TexFormat,
329 &datatype, &comps);
330
331 for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
332 const uint srcLevel = dstLevel - 1;
333 struct pipe_surface *srcSurf, *dstSurf;
334 const ubyte *srcData;
335 ubyte *dstData;
336
337 srcSurf = pipe->get_tex_surface(pipe, pt, face, srcLevel, zslice);
338 dstSurf = pipe->get_tex_surface(pipe, pt, face, dstLevel, zslice);
339
340 srcData = (ubyte *) ws->buffer_map(ws, srcSurf->buffer,
341 PIPE_BUFFER_USAGE_CPU_READ)
342 + srcSurf->offset;
343 dstData = (ubyte *) ws->buffer_map(ws, dstSurf->buffer,
344 PIPE_BUFFER_USAGE_CPU_WRITE)
345 + dstSurf->offset;
346
347 _mesa_generate_mipmap_level(target, datatype, comps,
348 0 /*border*/,
349 pt->width[srcLevel], pt->height[srcLevel], pt->depth[srcLevel],
350 srcSurf->pitch * srcSurf->cpp, /* stride in bytes */
351 srcData,
352 pt->width[dstLevel], pt->height[dstLevel], pt->depth[dstLevel],
353 dstSurf->pitch * dstSurf->cpp, /* stride in bytes */
354 dstData);
355
356 ws->buffer_unmap(ws, srcSurf->buffer);
357 ws->buffer_unmap(ws, dstSurf->buffer);
358
359 pipe_surface_reference(&srcSurf, NULL);
360 pipe_surface_reference(&dstSurf, NULL);
361 }
362 }
363
364
365 void
366 st_generate_mipmap(GLcontext *ctx, GLenum target,
367 struct gl_texture_object *texObj)
368 {
369 struct st_context *st = ctx->st;
370 struct pipe_texture *pt = st_get_texobj_texture(texObj);
371 const uint baseLevel = texObj->BaseLevel;
372 const uint lastLevel = pt->last_level;
373 uint dstLevel;
374
375 if (!st_render_mipmap(st, target, pt, baseLevel, lastLevel)) {
376 fallback_generate_mipmap(ctx, target, texObj);
377 }
378
379 /* Fill in the Mesa gl_texture_image fields */
380 for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
381 const uint srcLevel = dstLevel - 1;
382 const struct gl_texture_image *srcImage
383 = _mesa_get_tex_image(ctx, texObj, target, srcLevel);
384 struct gl_texture_image *dstImage;
385 struct st_texture_image *stImage;
386 uint dstWidth = pt->width[dstLevel];
387 uint dstHeight = pt->height[dstLevel];
388 uint dstDepth = pt->depth[dstLevel];
389 uint border = srcImage->Border;
390
391 dstImage = _mesa_get_tex_image(ctx, texObj, target, dstLevel);
392 if (!dstImage) {
393 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
394 return;
395 }
396
397 if (dstImage->ImageOffsets)
398 _mesa_free(dstImage->ImageOffsets);
399
400 /* Free old image data */
401 if (dstImage->Data)
402 ctx->Driver.FreeTexImageData(ctx, dstImage);
403
404 /* initialize new image */
405 _mesa_init_teximage_fields(ctx, target, dstImage, dstWidth, dstHeight,
406 dstDepth, border, srcImage->InternalFormat);
407
408 dstImage->TexFormat = srcImage->TexFormat;
409
410 stImage = (struct st_texture_image *) dstImage;
411 stImage->pt = pt;
412 }
413 }