st_cb_drawpixels.c revision 519aacef031e3271e16693308ca462346a8a160c
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   GLuint pipeFormat = st_choose_pipe_format(st->pipe, GL_RGBA, format, type);
104   int cpp = 4, pitch;
105   struct pipe_mipmap_tree *mt = CALLOC_STRUCT(pipe_mipmap_tree);
106
107   assert(pipeFormat);
108
109   pitch = width; /* XXX pad */
110
111   if (unpack->BufferObj) {
112      /*
113      mt->region = buffer_object_region(unpack->BufferObj);
114      */
115   }
116   else {
117      mt->region = st->pipe->region_alloc(st->pipe, cpp, pitch, height);
118      /* XXX do texstore() here */
119   }
120
121   mt->target = GL_TEXTURE_2D;
122   mt->internal_format = GL_RGBA;
123   mt->format = pipeFormat;
124   mt->first_level = 0;
125   mt->last_level = 0;
126   mt->width0 = width;
127   mt->height0 = height;
128   mt->depth0 = 1;
129   mt->cpp = cpp;
130   mt->compressed = 0;
131   mt->pitch = pitch;
132   mt->depth_pitch = 0;
133   mt->total_height = height;
134   mt->level[0].level_offset = 0;
135   mt->level[0].width = width;
136   mt->level[0].height = height;
137   mt->level[0].depth = 1;
138   mt->level[0].nr_images = 1;
139   mt->level[0].image_offset = NULL;
140   mt->refcount = 1;
141
142   return mt;
143}
144
145
146static void
147free_mipmap_tree(struct pipe_context *pipe, struct pipe_mipmap_tree *mt)
148{
149   pipe->region_release(pipe, &mt->region);
150}
151
152
153
154static void
155draw_quad(struct st_context *st, GLfloat x, GLfloat y, GLfloat z,
156          GLsizei width, GLsizei height)
157{
158   static const GLuint attribs[2] = {
159      VF_ATTRIB_POS,
160      VF_ATTRIB_TEX0
161   };
162   GLfloat verts[4][2][4]; /* four verts, two attribs, XYZW */
163   GLuint i;
164
165   /* lower-left */
166   verts[0][0][0] = x;
167   verts[0][0][1] = y;
168   verts[0][1][0] = 0.0;
169   verts[0][1][1] = 0.0;
170
171   /* lower-right */
172   verts[1][0][0] = x + width;
173   verts[1][0][1] = y;
174   verts[1][1][0] = 1.0;
175   verts[1][1][1] = 0.0;
176
177   /* upper-right */
178   verts[2][0][0] = x + width;
179   verts[2][0][1] = y + height;
180   verts[2][1][0] = 1.0;
181   verts[2][1][1] = 1.0;
182
183   /* upper-left */
184   verts[3][0][0] = x;
185   verts[3][0][1] = y + height;
186   verts[3][1][0] = 0.0;
187   verts[3][1][1] = 11.0;
188
189   /* same for all verts: */
190   for (i = 0; i < 4; i++) {
191      verts[i][0][2] = z;   /*Z*/
192      verts[i][0][3] = 1.0; /*W*/
193      verts[i][1][2] = 0.0; /*R*/
194      verts[i][1][3] = 1.0; /*Q*/
195   }
196
197   st->pipe->draw_vertices(st->pipe, GL_QUADS,
198                           4, (GLfloat *) verts, 2, attribs);
199}
200
201
202static void
203draw_textured_quad(struct st_context *st, GLfloat x, GLfloat y, GLfloat z,
204                   GLsizei width, GLsizei height, GLenum format, GLenum type,
205                   const struct gl_pixelstore_attrib *unpack,
206                   const GLvoid *pixels)
207{
208   static struct st_fragment_program *stfp = NULL;
209   struct pipe_mipmap_tree *mt;
210   struct pipe_setup_state setup;
211   struct pipe_fs_state fs;
212
213   /* setup state: just scissor */
214   memset(&setup, 0, sizeof(setup));
215   if (st->ctx->Scissor.Enabled)
216      setup.scissor = 1;
217   st->pipe->set_setup_state(st->pipe, &setup);
218
219   /* fragment shader state: color pass-through program */
220   if (!stfp) {
221      stfp = make_drawpixels_shader(st);
222   }
223   memset(&fs, 0, sizeof(fs));
224   fs.inputs_read = stfp->Base.Base.InputsRead;
225   fs.tokens = &stfp->tokens[0];
226   fs.constants = NULL;
227   st->pipe->set_fs_state(st->pipe, &fs);
228
229   /* mipmap tree state: */
230   mt = make_mipmap_tree(st, width, height, format, type, unpack, pixels);
231   st->pipe->set_texture_state(st->pipe, 0, mt);
232
233   /* draw! */
234   draw_quad(st, x, y, z, width, height);
235
236   /* restore GL state */
237   st->pipe->set_setup_state(st->pipe, &st->state.setup);
238   st->pipe->set_fs_state(st->pipe, &st->state.fs);
239
240   free_mipmap_tree(st->pipe, mt);
241}
242
243
244/**
245 * Check if a GL format/type combination is a match to the given pipe format.
246 * XXX probably move this to a re-usable place.
247 */
248static GLboolean
249compatible_formats(GLenum format, GLenum type, GLuint pipeFormat)
250{
251   static const GLuint one = 1;
252   GLubyte littleEndian = *((GLubyte *) &one);
253
254   if (pipeFormat == PIPE_FORMAT_U_R8_G8_B8_A8 &&
255       format == GL_RGBA &&
256       type == GL_UNSIGNED_BYTE &&
257       !littleEndian) {
258      return GL_TRUE;
259   }
260   else if (pipeFormat == PIPE_FORMAT_U_R8_G8_B8_A8 &&
261            format == GL_ABGR_EXT &&
262            type == GL_UNSIGNED_BYTE &&
263            littleEndian) {
264      return GL_TRUE;
265   }
266   else if (pipeFormat == PIPE_FORMAT_U_A8_R8_G8_B8 &&
267            format == GL_BGRA &&
268            type == GL_UNSIGNED_BYTE &&
269            littleEndian) {
270      return GL_TRUE;
271   }
272   else if (pipeFormat == PIPE_FORMAT_U_R5_G6_B5 &&
273            format == GL_RGB &&
274            type == GL_UNSIGNED_SHORT_5_6_5) {
275      /* endian don't care */
276      return GL_TRUE;
277   }
278   else if (pipeFormat == PIPE_FORMAT_U_R5_G6_B5 &&
279            format == GL_BGR &&
280            type == GL_UNSIGNED_SHORT_5_6_5_REV) {
281      /* endian don't care */
282      return GL_TRUE;
283   }
284   else if (pipeFormat == PIPE_FORMAT_U_S8 &&
285            format == GL_STENCIL_INDEX &&
286            type == GL_UNSIGNED_BYTE) {
287      return GL_TRUE;
288   }
289   else if (pipeFormat == PIPE_FORMAT_U_Z32 &&
290            format == GL_DEPTH_COMPONENT &&
291            type == GL_UNSIGNED_INT) {
292      return GL_TRUE;
293   }
294   /* XXX add more cases */
295   else {
296      return GL_FALSE;
297   }
298}
299
300
301/**
302 * Check if any per-fragment ops are enabled.
303 * XXX probably move this to a re-usable place.
304 */
305static GLboolean
306any_fragment_ops(const struct st_context *st)
307{
308   if (st->state.alpha_test.enabled ||
309       st->state.blend.blend_enable ||
310       st->state.blend.logicop_enable ||
311       st->state.depth.enabled)
312      /* XXX more checks */
313      return GL_TRUE;
314   else
315      return GL_FALSE;
316}
317
318
319/**
320 * Check if any pixel transfer ops are enabled.
321 * XXX probably move this to a re-usable place.
322 */
323static GLboolean
324any_pixel_transfer_ops(const struct st_context *st)
325{
326   if (st->ctx->Pixel.RedScale != 1.0 ||
327       st->ctx->Pixel.RedBias != 0.0 ||
328       st->ctx->Pixel.GreenScale != 1.0 ||
329       st->ctx->Pixel.GreenBias != 0.0 ||
330       st->ctx->Pixel.BlueScale != 1.0 ||
331       st->ctx->Pixel.BlueBias != 0.0 ||
332       st->ctx->Pixel.AlphaScale != 1.0 ||
333       st->ctx->Pixel.AlphaBias != 0.0 ||
334       st->ctx->Pixel.MapColorFlag)
335      /* XXX more checks */
336      return GL_TRUE;
337   else
338      return GL_FALSE;
339}
340
341
342/**
343 * Draw image with a blit, or other non-textured quad method.
344 */
345static void
346draw_blit(struct st_context *st,
347          GLsizei width, GLsizei height,
348          GLenum format, GLenum type, const GLvoid *pixels)
349{
350
351
352}
353
354
355/**
356 * Called via ctx->Driver.DrawPixels()
357 */
358static void
359st_drawpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
360              GLenum format, GLenum type,
361              const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels)
362{
363   struct st_context *st = ctx->st;
364   struct pipe_surface *ps;
365   GLuint bufferFormat;
366
367   if (format == GL_DEPTH_COMPONENT) {
368      ps = st->state.framebuffer.zbuf;
369   }
370   else if (format == GL_STENCIL_INDEX) {
371      ps = st->state.framebuffer.sbuf;
372   }
373   else {
374      ps = st->state.framebuffer.cbufs[0];
375   }
376
377   bufferFormat = ps->format;
378
379   if (any_fragment_ops(st) ||
380       any_pixel_transfer_ops(st) ||
381       !compatible_formats(format, type, ps->format)) {
382      /* textured quad */
383      draw_textured_quad(st, x, y, ctx->Current.RasterPos[2], width, height,
384                         format, type, unpack, pixels);
385   }
386   else {
387      /* blit */
388      draw_blit(st, width, height, format, type, pixels);
389   }
390}
391
392
393void st_init_drawpixels_functions(struct dd_function_table *functions)
394{
395   functions->DrawPixels = st_drawpixels;
396}
397
398