st_cb_drawpixels.c revision e51aa572934c39fe3c99470343f776be4e783f42
1/**************************************************************************
2 *
3 * Copyright 2007 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  * Authors:
30  *   Brian Paul
31  */
32
33#include "imports.h"
34
35#include "st_context.h"
36#include "st_atom.h"
37#include "st_draw.h"
38#include "st_program.h"
39#include "st_cb_drawpixels.h"
40#include "st_cb_texture.h"
41#include "st_format.h"
42#include "pipe/p_context.h"
43#include "pipe/p_defines.h"
44#include "pipe/tgsi/mesa/mesa_to_tgsi.h"
45#include "shader/prog_instruction.h"
46#include "vf/vf.h"
47
48
49
50/**
51 * Create a simple fragment shader that passes the texture color through
52 * to the fragment color.
53 */
54static struct st_fragment_program *
55make_drawpixels_shader(struct st_context *st)
56{
57   GLcontext *ctx = st->ctx;
58   struct st_fragment_program *stfp;
59   struct gl_program *p;
60   GLboolean b;
61
62   p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
63   if (!p)
64      return NULL;
65
66   p->NumInstructions = 2;
67   p->Instructions = _mesa_alloc_instructions(2);
68   if (!p->Instructions) {
69      ctx->Driver.DeleteProgram(ctx, p);
70      return NULL;
71   }
72   _mesa_init_instructions(p->Instructions, 2);
73   /* TEX result.color, fragment.texcoord[0], texture[0], 2D; */
74   p->Instructions[0].Opcode = OPCODE_TEX;
75   p->Instructions[0].DstReg.File = PROGRAM_OUTPUT;
76   p->Instructions[0].DstReg.Index = FRAG_RESULT_COLR;
77   p->Instructions[0].SrcReg[0].File = PROGRAM_INPUT;
78   p->Instructions[0].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
79   p->Instructions[0].TexSrcUnit = 0;
80   p->Instructions[0].TexSrcTarget = TEXTURE_2D_INDEX;
81   /* END; */
82   p->Instructions[1].Opcode = OPCODE_END;
83
84   p->InputsRead = FRAG_BIT_TEX0;
85   p->OutputsWritten = (1 << FRAG_RESULT_COLR);
86
87   stfp = (struct st_fragment_program *) p;
88   /* compile into tgsi format */
89   b = tgsi_mesa_compile_fp_program(&stfp->Base,
90                                    stfp->tokens, ST_FP_MAX_TOKENS);
91   assert(b);
92
93   return stfp;
94}
95
96
97static struct pipe_mipmap_tree *
98make_mipmap_tree(struct st_context *st,
99                 GLsizei width, GLsizei height, GLenum format, GLenum type,
100                 const struct gl_pixelstore_attrib *unpack,
101                 const GLvoid *pixels)
102{
103   struct pipe_context *pipe = st->pipe;
104   const struct gl_texture_format *mformat;
105   GLuint pipeFormat = st_choose_pipe_format(st->pipe, GL_RGBA, format, type);
106   int cpp = 4;
107   struct pipe_mipmap_tree *mt = CALLOC_STRUCT(pipe_mipmap_tree);
108   GLbitfield flags = PIPE_SURFACE_FLAG_TEXTURE;
109
110   mformat = st_ChooseTextureFormat(st->ctx, GL_RGBA, format, type);
111   assert(format);
112
113   pipeFormat = st_mesa_format_to_pipe_format(mformat->MesaFormat);
114   assert(pipeFormat);
115
116   if (unpack->BufferObj && unpack->BufferObj->Name) {
117      /*
118      mt->region = buffer_object_region(unpack->BufferObj);
119      */
120   }
121   else {
122      static const GLuint dstImageOffsets = 0;
123      GLboolean success;
124      GLubyte *dest;
125      GLuint pitch;
126
127      /* allocate texture region/storage */
128      mt->region = st->pipe->region_alloc(st->pipe, cpp, width, height, flags);
129      pitch = mt->region->pitch;
130
131      /* map texture region */
132      dest = pipe->region_map(pipe, mt->region);
133
134      /* put image into texture region */
135      success = mformat->StoreImage(st->ctx, 2,       /* dims */
136                                    GL_RGBA,          /* baseInternalFormat */
137                                    mformat,          /* gl_texture_format */
138                                    dest,             /* dest */
139                                    0, 0, 0,          /* dstX/Y/Zoffset */
140                                    pitch * cpp,      /* dstRowStride */
141                                    &dstImageOffsets, /* dstImageOffsets */
142                                    width, height, 1, /* size */
143                                    format, type,     /* src format/type */
144                                    pixels,           /* data source */
145                                    unpack);
146
147      /* unmap */
148      pipe->region_unmap(pipe, mt->region);
149
150      assert(success);
151   }
152
153   mt->target = GL_TEXTURE_2D;
154   mt->internal_format = GL_RGBA;
155   mt->format = pipeFormat;
156   mt->first_level = 0;
157   mt->last_level = 0;
158   mt->width0 = width;
159   mt->height0 = height;
160   mt->depth0 = 1;
161   mt->cpp = cpp;
162   mt->compressed = 0;
163   mt->pitch = mt->region->pitch;
164   mt->depth_pitch = 0;
165   mt->total_height = height;
166   mt->level[0].level_offset = 0;
167   mt->level[0].width = width;
168   mt->level[0].height = height;
169   mt->level[0].depth = 1;
170   mt->level[0].nr_images = 1;
171   mt->level[0].image_offset = NULL;
172   mt->refcount = 1;
173
174   return mt;
175}
176
177
178static void
179free_mipmap_tree(struct pipe_context *pipe, struct pipe_mipmap_tree *mt)
180{
181   pipe->region_release(pipe, &mt->region);
182   free(mt);
183}
184
185
186static void
187draw_quad(struct st_context *st, GLfloat x, GLfloat y, GLfloat z,
188          GLsizei width, GLsizei height)
189{
190   static const GLuint attribs[2] = {
191      VF_ATTRIB_POS,
192      VF_ATTRIB_TEX0
193   };
194   GLfloat verts[4][2][4]; /* four verts, two attribs, XYZW */
195   GLuint i;
196
197   /* lower-left */
198   verts[0][0][0] = x;
199   verts[0][0][1] = y;
200   verts[0][1][0] = 0.0;
201   verts[0][1][1] = 0.0;
202
203   /* lower-right */
204   verts[1][0][0] = x + width;
205   verts[1][0][1] = y;
206   verts[1][1][0] = 1.0;
207   verts[1][1][1] = 0.0;
208
209   /* upper-right */
210   verts[2][0][0] = x + width;
211   verts[2][0][1] = y + height;
212   verts[2][1][0] = 1.0;
213   verts[2][1][1] = 1.0;
214
215   /* upper-left */
216   verts[3][0][0] = x;
217   verts[3][0][1] = y + height;
218   verts[3][1][0] = 0.0;
219   verts[3][1][1] = 1.0;
220
221   /* same for all verts: */
222   for (i = 0; i < 4; i++) {
223      verts[i][0][2] = z;   /*Z*/
224      verts[i][0][3] = 1.0; /*W*/
225      verts[i][1][2] = 0.0; /*R*/
226      verts[i][1][3] = 1.0; /*Q*/
227   }
228
229   st->pipe->draw_vertices(st->pipe, GL_QUADS,
230                           4, (GLfloat *) verts, 2, attribs);
231}
232
233
234static void
235draw_textured_quad(struct st_context *st, GLfloat x, GLfloat y, GLfloat z,
236                   GLsizei width, GLsizei height, GLenum format, GLenum type,
237                   const struct gl_pixelstore_attrib *unpack,
238                   const GLvoid *pixels)
239{
240   struct pipe_mipmap_tree *mt;
241
242   /* setup state: just scissor */
243   {
244      struct pipe_setup_state setup;
245      memset(&setup, 0, sizeof(setup));
246      if (st->ctx->Scissor.Enabled)
247         setup.scissor = 1;
248      st->pipe->set_setup_state(st->pipe, &setup);
249   }
250
251   /* fragment shader state: color pass-through program */
252   {
253      static struct st_fragment_program *stfp = NULL;
254      struct pipe_fs_state fs;
255      if (!stfp) {
256         stfp = make_drawpixels_shader(st);
257      }
258      memset(&fs, 0, sizeof(fs));
259      fs.inputs_read = stfp->Base.Base.InputsRead;
260      fs.tokens = &stfp->tokens[0];
261      fs.constants = NULL;
262      st->pipe->set_fs_state(st->pipe, &fs);
263   }
264
265   /* mipmap tree state: */
266   {
267      mt = make_mipmap_tree(st, width, height, format, type, unpack, pixels);
268      st->pipe->set_texture_state(st->pipe, 0, mt);
269   }
270
271   /* draw textured quad */
272   draw_quad(st, x, y, z, width, height);
273
274   /* restore GL state */
275   st->pipe->set_setup_state(st->pipe, &st->state.setup);
276   st->pipe->set_fs_state(st->pipe, &st->state.fs);
277
278   free_mipmap_tree(st->pipe, mt);
279}
280
281
282/**
283 * Check if a GL format/type combination is a match to the given pipe format.
284 * XXX probably move this to a re-usable place.
285 */
286static GLboolean
287compatible_formats(GLenum format, GLenum type, GLuint pipeFormat)
288{
289   static const GLuint one = 1;
290   GLubyte littleEndian = *((GLubyte *) &one);
291
292   if (pipeFormat == PIPE_FORMAT_U_R8_G8_B8_A8 &&
293       format == GL_RGBA &&
294       type == GL_UNSIGNED_BYTE &&
295       !littleEndian) {
296      return GL_TRUE;
297   }
298   else if (pipeFormat == PIPE_FORMAT_U_R8_G8_B8_A8 &&
299            format == GL_ABGR_EXT &&
300            type == GL_UNSIGNED_BYTE &&
301            littleEndian) {
302      return GL_TRUE;
303   }
304   else if (pipeFormat == PIPE_FORMAT_U_A8_R8_G8_B8 &&
305            format == GL_BGRA &&
306            type == GL_UNSIGNED_BYTE &&
307            littleEndian) {
308      return GL_TRUE;
309   }
310   else if (pipeFormat == PIPE_FORMAT_U_R5_G6_B5 &&
311            format == GL_RGB &&
312            type == GL_UNSIGNED_SHORT_5_6_5) {
313      /* endian don't care */
314      return GL_TRUE;
315   }
316   else if (pipeFormat == PIPE_FORMAT_U_R5_G6_B5 &&
317            format == GL_BGR &&
318            type == GL_UNSIGNED_SHORT_5_6_5_REV) {
319      /* endian don't care */
320      return GL_TRUE;
321   }
322   else if (pipeFormat == PIPE_FORMAT_U_S8 &&
323            format == GL_STENCIL_INDEX &&
324            type == GL_UNSIGNED_BYTE) {
325      return GL_TRUE;
326   }
327   else if (pipeFormat == PIPE_FORMAT_U_Z32 &&
328            format == GL_DEPTH_COMPONENT &&
329            type == GL_UNSIGNED_INT) {
330      return GL_TRUE;
331   }
332   /* XXX add more cases */
333   else {
334      return GL_FALSE;
335   }
336}
337
338
339/**
340 * Check if any per-fragment ops are enabled.
341 * XXX probably move this to a re-usable place.
342 */
343static GLboolean
344any_fragment_ops(const struct st_context *st)
345{
346   if (st->state.alpha_test.enabled ||
347       st->state.blend.blend_enable ||
348       st->state.blend.logicop_enable ||
349       st->state.depth.enabled)
350      /* XXX more checks */
351      return GL_TRUE;
352   else
353      return GL_FALSE;
354}
355
356
357/**
358 * Check if any pixel transfer ops are enabled.
359 * XXX probably move this to a re-usable place.
360 */
361static GLboolean
362any_pixel_transfer_ops(const struct st_context *st)
363{
364   if (st->ctx->Pixel.RedScale != 1.0 ||
365       st->ctx->Pixel.RedBias != 0.0 ||
366       st->ctx->Pixel.GreenScale != 1.0 ||
367       st->ctx->Pixel.GreenBias != 0.0 ||
368       st->ctx->Pixel.BlueScale != 1.0 ||
369       st->ctx->Pixel.BlueBias != 0.0 ||
370       st->ctx->Pixel.AlphaScale != 1.0 ||
371       st->ctx->Pixel.AlphaBias != 0.0 ||
372       st->ctx->Pixel.MapColorFlag)
373      /* XXX more checks */
374      return GL_TRUE;
375   else
376      return GL_FALSE;
377}
378
379
380/**
381 * Draw image with a blit, or other non-textured quad method.
382 */
383static void
384draw_blit(struct st_context *st,
385          GLsizei width, GLsizei height,
386          GLenum format, GLenum type, const GLvoid *pixels)
387{
388
389
390}
391
392
393/**
394 * Called via ctx->Driver.DrawPixels()
395 */
396static void
397st_drawpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
398              GLenum format, GLenum type,
399              const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels)
400{
401   struct st_context *st = ctx->st;
402   struct pipe_surface *ps;
403   GLuint bufferFormat;
404
405   if (format == GL_DEPTH_COMPONENT) {
406      ps = st->state.framebuffer.zbuf;
407   }
408   else if (format == GL_STENCIL_INDEX) {
409      ps = st->state.framebuffer.sbuf;
410   }
411   else {
412      ps = st->state.framebuffer.cbufs[0];
413   }
414
415   bufferFormat = ps->format;
416
417   if (any_fragment_ops(st) ||
418       any_pixel_transfer_ops(st) ||
419       !compatible_formats(format, type, ps->format)) {
420      /* textured quad */
421      draw_textured_quad(st, x, y, ctx->Current.RasterPos[2], width, height,
422                         format, type, unpack, pixels);
423   }
424   else {
425      /* blit */
426      draw_blit(st, width, height, format, type, pixels);
427   }
428}
429
430
431void st_init_drawpixels_functions(struct dd_function_table *functions)
432{
433   functions->DrawPixels = st_drawpixels;
434}
435
436