Merge branch 'upstream-gallium-0.1' into nouveau-gallium-0.1
[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 "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_texture.h"
47 #include "st_cb_drawpixels.h"
48 #include "st_cb_texture.h"
49
50
51
52 static struct st_fragment_program *
53 make_tex_fragment_program(GLcontext *ctx)
54 {
55 struct st_fragment_program *stfp;
56 struct gl_program *p;
57 GLuint ic = 0;
58
59 p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
60 if (!p)
61 return NULL;
62
63 p->NumInstructions = 2;
64
65 p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
66 if (!p->Instructions) {
67 ctx->Driver.DeleteProgram(ctx, p);
68 return NULL;
69 }
70 _mesa_init_instructions(p->Instructions, p->NumInstructions);
71
72 /* TEX result.color, fragment.texcoord[0], texture[0], 2D; */
73 p->Instructions[ic].Opcode = OPCODE_TEX;
74 p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
75 p->Instructions[ic].DstReg.Index = FRAG_RESULT_COLR;
76 p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
77 p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
78 p->Instructions[ic].TexSrcUnit = 0;
79 p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX;
80 ic++;
81
82 /* END; */
83 p->Instructions[ic++].Opcode = OPCODE_END;
84
85 assert(ic == p->NumInstructions);
86
87 p->InputsRead = FRAG_BIT_TEX0;
88 p->OutputsWritten = (1 << FRAG_RESULT_COLR);
89
90 stfp = (struct st_fragment_program *) p;
91
92 st_translate_fragment_program(ctx->st, stfp, NULL,
93 stfp->tokens, ST_MAX_SHADER_TOKENS);
94
95 return stfp;
96 }
97
98
99
100
101 /**
102 * one-time init for generate mipmap
103 * XXX Note: there may be other times we need no-op/simple state like this.
104 * In that case, some code refactoring would be good.
105 */
106 void
107 st_init_generate_mipmap(struct st_context *st)
108 {
109 struct pipe_context *pipe = st->pipe;
110 struct pipe_blend_state blend;
111 struct pipe_rasterizer_state rasterizer;
112 struct pipe_depth_stencil_alpha_state depthstencil;
113
114 /* we don't use blending, but need to set valid values */
115 memset(&blend, 0, sizeof(blend));
116 blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE;
117 blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE;
118 blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
119 blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
120 blend.colormask = PIPE_MASK_RGBA;
121 st->gen_mipmap.blend_cso = pipe->create_blend_state(pipe, &blend);
122
123 memset(&depthstencil, 0, sizeof(depthstencil));
124 st->gen_mipmap.depthstencil_cso = pipe->create_depth_stencil_alpha_state(pipe, &depthstencil);
125
126 /* Note: we're assuming zero is valid for all non-specified fields */
127 memset(&rasterizer, 0, sizeof(rasterizer));
128 rasterizer.front_winding = PIPE_WINDING_CW;
129 rasterizer.cull_mode = PIPE_WINDING_NONE;
130 st->gen_mipmap.rasterizer_cso = pipe->create_rasterizer_state(pipe, &rasterizer);
131
132 st->gen_mipmap.stfp = make_tex_fragment_program(st->ctx);
133 st->gen_mipmap.stvp = st_make_passthrough_vertex_shader(st, GL_FALSE);
134 }
135
136
137 void
138 st_destroy_generate_mipmpap(struct st_context *st)
139 {
140 struct pipe_context *pipe = st->pipe;
141
142 pipe->delete_blend_state(pipe, st->gen_mipmap.blend_cso);
143 pipe->delete_depth_stencil_alpha_state(pipe, st->gen_mipmap.depthstencil_cso);
144 pipe->delete_rasterizer_state(pipe, st->gen_mipmap.rasterizer_cso);
145
146 /* XXX free stfp, stvp */
147 }
148
149
150 static void
151 simple_viewport(struct pipe_context *pipe, uint width, uint height)
152 {
153 struct pipe_viewport_state vp;
154
155 vp.scale[0] = 0.5 * width;
156 vp.scale[1] = -0.5 * height;
157 vp.scale[2] = 1.0;
158 vp.scale[3] = 1.0;
159 vp.translate[0] = 0.5 * width;
160 vp.translate[1] = 0.5 * height;
161 vp.translate[2] = 0.0;
162 vp.translate[3] = 0.0;
163
164 pipe->set_viewport_state(pipe, &vp);
165 }
166
167
168
169 /*
170 * Draw simple [-1,1]x[-1,1] quad
171 */
172 static void
173 draw_quad(GLcontext *ctx)
174 {
175 GLfloat verts[4][2][4]; /* four verts, two attribs, XYZW */
176 GLuint i;
177 GLfloat sLeft = 0.0, sRight = 1.0;
178 GLfloat tTop = 1.0, tBot = 0.0;
179 GLfloat x0 = -1.0, x1 = 1.0;
180 GLfloat y0 = -1.0, y1 = 1.0;
181
182 /* upper-left */
183 verts[0][0][0] = x0; /* attr[0].x */
184 verts[0][0][1] = y0; /* attr[0].y */
185 verts[0][1][0] = sLeft; /* attr[1].s */
186 verts[0][1][1] = tTop; /* attr[1].t */
187
188 /* upper-right */
189 verts[1][0][0] = x1;
190 verts[1][0][1] = y0;
191 verts[1][1][0] = sRight;
192 verts[1][1][1] = tTop;
193
194 /* lower-right */
195 verts[2][0][0] = x1;
196 verts[2][0][1] = y1;
197 verts[2][1][0] = sRight;
198 verts[2][1][1] = tBot;
199
200 /* lower-left */
201 verts[3][0][0] = x0;
202 verts[3][0][1] = y1;
203 verts[3][1][0] = sLeft;
204 verts[3][1][1] = tBot;
205
206 /* same for all verts: */
207 for (i = 0; i < 4; i++) {
208 verts[i][0][2] = 0.0; /*Z*/
209 verts[i][0][3] = 1.0; /*W*/
210 verts[i][1][2] = 0.0; /*R*/
211 verts[i][1][3] = 1.0; /*Q*/
212 }
213
214 st_draw_vertices(ctx, PIPE_PRIM_QUADS, 4, (float *) verts, 2, GL_TRUE);
215 }
216
217
218
219 /**
220 * Generate mipmap levels using hardware rendering.
221 * \return TRUE if successful, FALSE if not possible
222 */
223 static boolean
224 st_render_mipmap(struct st_context *st,
225 GLenum target,
226 struct pipe_texture *pt,
227 uint baseLevel, uint lastLevel)
228 {
229 struct pipe_context *pipe = st->pipe;
230 struct pipe_screen *screen = pipe->screen;
231 struct pipe_framebuffer_state fb;
232 struct pipe_sampler_state sampler;
233 void *sampler_cso;
234 const uint face = _mesa_tex_target_to_face(target), zslice = 0;
235 /*const uint first_level_save = pt->first_level;*/
236 uint dstLevel;
237
238 assert(target != GL_TEXTURE_3D); /* not done yet */
239
240 /* check if we can render in the texture's format */
241 if (!screen->is_format_supported(screen, pt->format, PIPE_SURFACE)) {
242 return FALSE;
243 }
244
245 /* init framebuffer state */
246 memset(&fb, 0, sizeof(fb));
247 fb.num_cbufs = 1;
248
249 /* sampler state */
250 memset(&sampler, 0, sizeof(sampler));
251 sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
252 sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
253 sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
254 sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
255 sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR;
256 sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
257 sampler.normalized_coords = 1;
258
259
260 /* bind CSOs */
261 pipe->bind_blend_state(pipe, st->gen_mipmap.blend_cso);
262 pipe->bind_depth_stencil_alpha_state(pipe, st->gen_mipmap.depthstencil_cso);
263 pipe->bind_rasterizer_state(pipe, st->gen_mipmap.rasterizer_cso);
264
265 /* bind shaders */
266 pipe->bind_fs_state(pipe, st->gen_mipmap.stfp->cso->data);
267 pipe->bind_vs_state(pipe, st->gen_mipmap.stvp->cso->data);
268
269 /*
270 * XXX for small mipmap levels, it may be faster to use the software
271 * fallback path...
272 */
273 for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
274 const uint srcLevel = dstLevel - 1;
275
276 /*
277 * Setup framebuffer / dest surface
278 */
279 fb.cbufs[0] = screen->get_tex_surface(screen, pt, face, dstLevel, zslice);
280 pipe->set_framebuffer_state(pipe, &fb);
281
282 /*
283 * Setup sampler state
284 */
285 sampler.min_lod = sampler.max_lod = srcLevel;
286 sampler_cso = pipe->create_sampler_state(pipe, &sampler);
287 pipe->bind_sampler_state(pipe, 0, sampler_cso);
288
289 simple_viewport(pipe, pt->width[dstLevel], pt->height[dstLevel]);
290
291 /*
292 * Setup src texture, override pt->first_level so we sample from
293 * the right mipmap level.
294 */
295 /*pt->first_level = srcLevel;*/
296 pipe->set_sampler_texture(pipe, 0, pt);
297
298 draw_quad(st->ctx);
299
300 pipe->delete_sampler_state(pipe, sampler_cso);
301 }
302
303 /* restore first_level */
304 /*pt->first_level = first_level_save;*/
305
306 /* restore pipe state */
307 if (st->state.rasterizer)
308 pipe->bind_rasterizer_state(pipe, st->state.rasterizer->data);
309 if (st->state.fs)
310 pipe->bind_fs_state(pipe, st->state.fs->data);
311 if (st->state.vs)
312 pipe->bind_vs_state(pipe, st->state.vs->cso->data);
313 if (st->state.sampler[0])
314 pipe->bind_sampler_state(pipe, 0, st->state.sampler[0]->data);
315 pipe->set_sampler_texture(pipe, 0, st->state.sampler_texture[0]);
316 pipe->set_viewport_state(pipe, &st->state.viewport);
317
318 return TRUE;
319 }
320
321
322 static void
323 fallback_generate_mipmap(GLcontext *ctx, GLenum target,
324 struct gl_texture_object *texObj)
325 {
326 struct pipe_context *pipe = ctx->st->pipe;
327 struct pipe_screen *screen = pipe->screen;
328 struct pipe_winsys *ws = pipe->winsys;
329 struct pipe_texture *pt = st_get_texobj_texture(texObj);
330 const uint baseLevel = texObj->BaseLevel;
331 const uint lastLevel = pt->last_level;
332 const uint face = _mesa_tex_target_to_face(target), zslice = 0;
333 uint dstLevel;
334 GLenum datatype;
335 GLuint comps;
336
337 assert(target != GL_TEXTURE_3D); /* not done yet */
338
339 _mesa_format_to_type_and_comps(texObj->Image[face][baseLevel]->TexFormat,
340 &datatype, &comps);
341
342 for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
343 const uint srcLevel = dstLevel - 1;
344 struct pipe_surface *srcSurf, *dstSurf;
345 const ubyte *srcData;
346 ubyte *dstData;
347
348 srcSurf = screen->get_tex_surface(screen, pt, face, srcLevel, zslice);
349 dstSurf = screen->get_tex_surface(screen, pt, face, dstLevel, zslice);
350
351 srcData = (ubyte *) ws->buffer_map(ws, srcSurf->buffer,
352 PIPE_BUFFER_USAGE_CPU_READ)
353 + srcSurf->offset;
354 dstData = (ubyte *) ws->buffer_map(ws, dstSurf->buffer,
355 PIPE_BUFFER_USAGE_CPU_WRITE)
356 + dstSurf->offset;
357
358 _mesa_generate_mipmap_level(target, datatype, comps,
359 0 /*border*/,
360 pt->width[srcLevel], pt->height[srcLevel], pt->depth[srcLevel],
361 srcSurf->pitch * srcSurf->cpp, /* stride in bytes */
362 srcData,
363 pt->width[dstLevel], pt->height[dstLevel], pt->depth[dstLevel],
364 dstSurf->pitch * dstSurf->cpp, /* stride in bytes */
365 dstData);
366
367 ws->buffer_unmap(ws, srcSurf->buffer);
368 ws->buffer_unmap(ws, dstSurf->buffer);
369
370 pipe_surface_reference(&srcSurf, NULL);
371 pipe_surface_reference(&dstSurf, NULL);
372 }
373 }
374
375
376 void
377 st_generate_mipmap(GLcontext *ctx, GLenum target,
378 struct gl_texture_object *texObj)
379 {
380 struct st_context *st = ctx->st;
381 struct pipe_texture *pt = st_get_texobj_texture(texObj);
382 const uint baseLevel = texObj->BaseLevel;
383 const uint lastLevel = pt->last_level;
384 uint dstLevel;
385
386 if (!st_render_mipmap(st, target, pt, baseLevel, lastLevel)) {
387 fallback_generate_mipmap(ctx, target, texObj);
388 }
389
390 /* Fill in the Mesa gl_texture_image fields */
391 for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
392 const uint srcLevel = dstLevel - 1;
393 const struct gl_texture_image *srcImage
394 = _mesa_get_tex_image(ctx, texObj, target, srcLevel);
395 struct gl_texture_image *dstImage;
396 struct st_texture_image *stImage;
397 uint dstWidth = pt->width[dstLevel];
398 uint dstHeight = pt->height[dstLevel];
399 uint dstDepth = pt->depth[dstLevel];
400 uint border = srcImage->Border;
401
402 dstImage = _mesa_get_tex_image(ctx, texObj, target, dstLevel);
403 if (!dstImage) {
404 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
405 return;
406 }
407
408 if (dstImage->ImageOffsets)
409 _mesa_free(dstImage->ImageOffsets);
410
411 /* Free old image data */
412 if (dstImage->Data)
413 ctx->Driver.FreeTexImageData(ctx, dstImage);
414
415 /* initialize new image */
416 _mesa_init_teximage_fields(ctx, target, dstImage, dstWidth, dstHeight,
417 dstDepth, border, srcImage->InternalFormat);
418
419 dstImage->TexFormat = srcImage->TexFormat;
420
421 stImage = (struct st_texture_image *) dstImage;
422 stImage->pt = pt;
423 }
424 }