st_cb_drawpixels.c revision 294401814d1d89cc731de1c22c25333aa5d59374
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_cache.h"
38#include "st_draw.h"
39#include "st_program.h"
40#include "st_cb_drawpixels.h"
41#include "st_cb_texture.h"
42#include "st_draw.h"
43#include "st_format.h"
44#include "pipe/p_context.h"
45#include "pipe/p_defines.h"
46#include "pipe/tgsi/mesa/mesa_to_tgsi.h"
47#include "shader/prog_instruction.h"
48#include "vf/vf.h"
49
50
51
52/**
53 * Create a simple fragment shader that does a TEX() instruction to get
54 * the fragment color.
55 */
56static struct st_fragment_program *
57make_fragment_shader(struct st_context *st)
58{
59   GLcontext *ctx = st->ctx;
60   struct st_fragment_program *stfp;
61   struct gl_program *p;
62   GLboolean b;
63
64   p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
65   if (!p)
66      return NULL;
67
68   p->NumInstructions = 2;
69   p->Instructions = _mesa_alloc_instructions(2);
70   if (!p->Instructions) {
71      ctx->Driver.DeleteProgram(ctx, p);
72      return NULL;
73   }
74   _mesa_init_instructions(p->Instructions, 2);
75   /* TEX result.color, fragment.texcoord[0], texture[0], 2D; */
76   p->Instructions[0].Opcode = OPCODE_TEX;
77   p->Instructions[0].DstReg.File = PROGRAM_OUTPUT;
78   p->Instructions[0].DstReg.Index = FRAG_RESULT_COLR;
79   p->Instructions[0].SrcReg[0].File = PROGRAM_INPUT;
80   p->Instructions[0].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
81   p->Instructions[0].TexSrcUnit = 0;
82   p->Instructions[0].TexSrcTarget = TEXTURE_2D_INDEX;
83   /* END; */
84   p->Instructions[1].Opcode = OPCODE_END;
85
86   p->InputsRead = FRAG_BIT_TEX0;
87   p->OutputsWritten = (1 << FRAG_RESULT_COLR);
88
89   stfp = (struct st_fragment_program *) p;
90   /* compile into tgsi format */
91   b = tgsi_mesa_compile_fp_program(&stfp->Base,
92                                    stfp->tokens, ST_FP_MAX_TOKENS);
93   assert(b);
94
95   return stfp;
96}
97
98
99/**
100 * Create a simple vertex shader that just passes through the
101 * vertex position and color.
102 */
103static struct st_vertex_program *
104make_vertex_shader(struct st_context *st)
105{
106   GLcontext *ctx = st->ctx;
107   struct st_vertex_program *stvp;
108   struct gl_program *p;
109   GLboolean b;
110
111   p = ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0);
112   if (!p)
113      return NULL;
114
115   p->NumInstructions = 3;
116   p->Instructions = _mesa_alloc_instructions(3);
117   if (!p->Instructions) {
118      ctx->Driver.DeleteProgram(ctx, p);
119      return NULL;
120   }
121   _mesa_init_instructions(p->Instructions, 3);
122   /* MOV result.pos, vertex.pos; */
123   p->Instructions[0].Opcode = OPCODE_MOV;
124   p->Instructions[0].DstReg.File = PROGRAM_OUTPUT;
125   p->Instructions[0].DstReg.Index = VERT_RESULT_HPOS;
126   p->Instructions[0].SrcReg[0].File = PROGRAM_INPUT;
127   p->Instructions[0].SrcReg[0].Index = VERT_ATTRIB_POS;
128   /* MOV result.color, vertex.color; */
129   p->Instructions[1].Opcode = OPCODE_MOV;
130   p->Instructions[1].DstReg.File = PROGRAM_OUTPUT;
131   p->Instructions[1].DstReg.Index = VERT_RESULT_TEX0;
132   p->Instructions[1].SrcReg[0].File = PROGRAM_INPUT;
133   p->Instructions[1].SrcReg[0].Index = VERT_ATTRIB_TEX0;
134   /* END; */
135   p->Instructions[2].Opcode = OPCODE_END;
136
137   p->InputsRead = VERT_BIT_POS | VERT_BIT_TEX0;
138   p->OutputsWritten = ((1 << VERT_RESULT_TEX0) |
139                        (1 << VERT_RESULT_HPOS));
140
141   stvp = (struct st_vertex_program *) p;
142   /* compile into tgsi format */
143   b = tgsi_mesa_compile_vp_program(&stvp->Base,
144                                    stvp->tokens, ST_FP_MAX_TOKENS);
145   assert(b);
146
147   return stvp;
148}
149
150
151
152static struct pipe_mipmap_tree *
153make_mipmap_tree(struct st_context *st,
154                 GLsizei width, GLsizei height, GLenum format, GLenum type,
155                 const struct gl_pixelstore_attrib *unpack,
156                 const GLvoid *pixels)
157{
158   struct pipe_context *pipe = st->pipe;
159   const struct gl_texture_format *mformat;
160   const GLbitfield flags = PIPE_SURFACE_FLAG_TEXTURE;
161   struct pipe_mipmap_tree *mt;
162   GLuint pipeFormat, cpp;
163
164   mformat = st_ChooseTextureFormat(st->ctx, GL_RGBA, format, type);
165   assert(mformat);
166
167   pipeFormat = st_mesa_format_to_pipe_format(mformat->MesaFormat);
168   assert(pipeFormat);
169   cpp = st_sizeof_format(pipeFormat);
170
171   mt = CALLOC_STRUCT(pipe_mipmap_tree);
172
173   if (unpack->BufferObj && unpack->BufferObj->Name) {
174      /*
175      mt->region = buffer_object_region(unpack->BufferObj);
176      */
177   }
178   else {
179      static const GLuint dstImageOffsets = 0;
180      GLboolean success;
181      GLubyte *dest;
182      GLuint pitch;
183
184      /* allocate texture region/storage */
185      mt->region = st->pipe->region_alloc(st->pipe, cpp, width, height, flags);
186      pitch = mt->region->pitch;
187
188      /* map texture region */
189      dest = pipe->region_map(pipe, mt->region);
190
191      /* Put image into texture region.
192       * Note that the image is actually going to be upside down in
193       * the texture.  We deal with that with texcoords.
194       */
195      success = mformat->StoreImage(st->ctx, 2,       /* dims */
196                                    GL_RGBA,          /* baseInternalFormat */
197                                    mformat,          /* gl_texture_format */
198                                    dest,             /* dest */
199                                    0, 0, 0,          /* dstX/Y/Zoffset */
200                                    pitch * cpp,      /* dstRowStride, bytes */
201                                    &dstImageOffsets, /* dstImageOffsets */
202                                    width, height, 1, /* size */
203                                    format, type,     /* src format/type */
204                                    pixels,           /* data source */
205                                    unpack);
206
207      /* unmap */
208      pipe->region_unmap(pipe, mt->region);
209
210      assert(success);
211   }
212
213   mt->target = PIPE_TEXTURE_2D;
214   mt->internal_format = GL_RGBA;
215   mt->format = pipeFormat;
216   mt->first_level = 0;
217   mt->last_level = 0;
218   mt->width0 = width;
219   mt->height0 = height;
220   mt->depth0 = 1;
221   mt->cpp = cpp;
222   mt->compressed = 0;
223   mt->pitch = mt->region->pitch;
224   mt->depth_pitch = 0;
225   mt->total_height = height;
226   mt->level[0].level_offset = 0;
227   mt->level[0].width = width;
228   mt->level[0].height = height;
229   mt->level[0].depth = 1;
230   mt->level[0].nr_images = 1;
231   mt->level[0].image_offset = NULL;
232   mt->refcount = 1;
233
234   return mt;
235}
236
237
238static void
239free_mipmap_tree(struct pipe_context *pipe, struct pipe_mipmap_tree *mt)
240{
241   pipe->region_release(pipe, &mt->region);
242   free(mt);
243}
244
245
246/**
247 * Draw textured quad.
248 * Coords are window coords with y=0=bottom.
249 */
250static void
251draw_quad(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z,
252          GLfloat x1, GLfloat y1)
253{
254   static const GLuint attribs[2] = {
255      0, /* pos */
256      8  /* tex0 */
257   };
258   GLfloat verts[4][2][4]; /* four verts, two attribs, XYZW */
259   GLuint i;
260
261   /* upper-left */
262   verts[0][0][0] = x0;
263   verts[0][0][1] = y0;
264   verts[0][1][0] = 0.0;
265   verts[0][1][1] = 0.0;
266
267   /* upper-right */
268   verts[1][0][0] = x1;
269   verts[1][0][1] = y0;
270   verts[1][1][0] = 1.0;
271   verts[1][1][1] = 0.0;
272
273   /* lower-right */
274   verts[2][0][0] = x1;
275   verts[2][0][1] = y1;
276   verts[2][1][0] = 1.0;
277   verts[2][1][1] = 1.0;
278
279   /* lower-left */
280   verts[3][0][0] = x0;
281   verts[3][0][1] = y1;
282   verts[3][1][0] = 0.0;
283   verts[3][1][1] = 1.0;
284
285   /* same for all verts: */
286   for (i = 0; i < 4; i++) {
287      verts[i][0][2] = z;   /*Z*/
288      verts[i][0][3] = 1.0; /*W*/
289      verts[i][1][2] = 0.0; /*R*/
290      verts[i][1][3] = 1.0; /*Q*/
291   }
292
293   st_draw_vertices(ctx, PIPE_PRIM_QUADS, 4, (float *) verts, 2, attribs);
294}
295
296
297static void
298draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z,
299                   GLsizei width, GLsizei height, GLenum format, GLenum type,
300                   const struct gl_pixelstore_attrib *unpack,
301                   const GLvoid *pixels)
302{
303   const GLuint unit = 0;
304   struct pipe_context *pipe = ctx->st->pipe;
305   struct pipe_mipmap_tree *mt;
306   GLfloat x0, y0, x1, y1;
307   GLuint maxWidth, maxHeight;
308
309   /* limit checks */
310   /* XXX if DrawPixels image is larger than max texture size, break
311    * it up into chunks.
312    */
313   pipe->max_texture_size(pipe, PIPE_TEXTURE_2D, &maxWidth, &maxHeight, NULL);
314   assert(width <= maxWidth);
315   assert(height <= maxHeight);
316
317   /* setup state: just scissor */
318   {
319      struct pipe_rasterizer_state  setup;
320      struct pipe_rasterizer_state *cached;
321      memset(&setup, 0, sizeof(setup));
322      if (ctx->Scissor.Enabled)
323         setup.scissor = 1;
324      cached = st_cached_rasterizer_state(ctx->st, &setup);
325      pipe->bind_rasterizer_state(pipe, cached);
326   }
327
328   /* fragment shader state: TEX lookup program */
329   {
330      static struct st_fragment_program *stfp = NULL;
331      struct pipe_shader_state fs;
332      if (!stfp) {
333         stfp = make_fragment_shader(ctx->st);
334      }
335      memset(&fs, 0, sizeof(fs));
336      fs.inputs_read = stfp->Base.Base.InputsRead;
337      fs.tokens = &stfp->tokens[0];
338      pipe->set_fs_state(pipe, &fs);
339   }
340
341   /* vertex shader state: position + texcoord pass-through */
342   {
343      static struct st_vertex_program *stvp = NULL;
344      struct pipe_shader_state vs;
345      if (!stvp) {
346         stvp = make_vertex_shader(ctx->st);
347      }
348      memset(&vs, 0, sizeof(vs));
349      vs.inputs_read = stvp->Base.Base.InputsRead;
350      vs.outputs_written = stvp->Base.Base.OutputsWritten;
351      vs.tokens = &stvp->tokens[0];
352      pipe->set_vs_state(pipe, &vs);
353   }
354
355   /* texture sampling state: */
356   {
357      struct pipe_sampler_state sampler;
358      memset(&sampler, 0, sizeof(sampler));
359      sampler.wrap_s = PIPE_TEX_WRAP_REPEAT;
360      sampler.wrap_t = PIPE_TEX_WRAP_REPEAT;
361      sampler.wrap_r = PIPE_TEX_WRAP_REPEAT;
362      sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
363      sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
364      sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
365      const struct pipe_sampler_state *state = st_cached_sampler_state(ctx->st, &sampler);
366      pipe->bind_sampler_state(pipe, unit, state);
367   }
368
369   /* viewport state: viewport matching window dims */
370   {
371      const float width = ctx->DrawBuffer->Width;
372      const float height = ctx->DrawBuffer->Height;
373      struct pipe_viewport_state vp;
374      vp.scale[0] =  0.5 * width;
375      vp.scale[1] = -0.5 * height;
376      vp.scale[2] = 0.5;
377      vp.scale[3] = 1.0;
378      vp.translate[0] = 0.5 * width;
379      vp.translate[1] = 0.5 * height;
380      vp.translate[2] = 0.5;
381      vp.translate[3] = 0.0;
382      pipe->set_viewport_state(pipe, &vp);
383   }
384
385   /* mipmap tree state: */
386   {
387      mt = make_mipmap_tree(ctx->st, width, height, format, type,
388                            unpack, pixels);
389      pipe->set_texture_state(pipe, unit, mt);
390   }
391
392   /* Compute window coords (y=0=bottom) with pixel zoom.
393    * Recall that these coords are transformed by the current
394    * vertex shader and viewport transformation.
395    */
396   x0 = x;
397   x1 = x + width * ctx->Pixel.ZoomX;
398   y0 = y;
399   y1 = y + height * ctx->Pixel.ZoomY;
400
401   /* draw textured quad */
402   draw_quad(ctx, x0, y0, z, x1, y1);
403
404   /* restore GL state */
405   pipe->bind_rasterizer_state(pipe, ctx->st->state.rasterizer);
406   pipe->set_fs_state(pipe, &ctx->st->state.fs);
407   pipe->set_vs_state(pipe, &ctx->st->state.vs);
408   pipe->set_texture_state(pipe, unit, ctx->st->state.texture[unit]);
409   pipe->bind_sampler_state(pipe, unit, ctx->st->state.sampler[unit]);
410   pipe->set_viewport_state(pipe, &ctx->st->state.viewport);
411
412   free_mipmap_tree(pipe, mt);
413}
414
415
416/**
417 * Check if a GL format/type combination is a match to the given pipe format.
418 * XXX probably move this to a re-usable place.
419 */
420static GLboolean
421compatible_formats(GLenum format, GLenum type, GLuint pipeFormat)
422{
423   static const GLuint one = 1;
424   GLubyte littleEndian = *((GLubyte *) &one);
425
426   if (pipeFormat == PIPE_FORMAT_U_R8_G8_B8_A8 &&
427       format == GL_RGBA &&
428       type == GL_UNSIGNED_BYTE &&
429       !littleEndian) {
430      return GL_TRUE;
431   }
432   else if (pipeFormat == PIPE_FORMAT_U_R8_G8_B8_A8 &&
433            format == GL_ABGR_EXT &&
434            type == GL_UNSIGNED_BYTE &&
435            littleEndian) {
436      return GL_TRUE;
437   }
438   else if (pipeFormat == PIPE_FORMAT_U_A8_R8_G8_B8 &&
439            format == GL_BGRA &&
440            type == GL_UNSIGNED_BYTE &&
441            littleEndian) {
442      return GL_TRUE;
443   }
444   else if (pipeFormat == PIPE_FORMAT_U_R5_G6_B5 &&
445            format == GL_RGB &&
446            type == GL_UNSIGNED_SHORT_5_6_5) {
447      /* endian don't care */
448      return GL_TRUE;
449   }
450   else if (pipeFormat == PIPE_FORMAT_U_R5_G6_B5 &&
451            format == GL_BGR &&
452            type == GL_UNSIGNED_SHORT_5_6_5_REV) {
453      /* endian don't care */
454      return GL_TRUE;
455   }
456   else if (pipeFormat == PIPE_FORMAT_U_S8 &&
457            format == GL_STENCIL_INDEX &&
458            type == GL_UNSIGNED_BYTE) {
459      return GL_TRUE;
460   }
461   else if (pipeFormat == PIPE_FORMAT_U_Z32 &&
462            format == GL_DEPTH_COMPONENT &&
463            type == GL_UNSIGNED_INT) {
464      return GL_TRUE;
465   }
466   /* XXX add more cases */
467   else {
468      return GL_FALSE;
469   }
470}
471
472
473/**
474 * Check if any per-fragment ops are enabled.
475 * XXX probably move this to a re-usable place.
476 */
477static GLboolean
478any_fragment_ops(const struct st_context *st)
479{
480   if (st->state.alpha_test.enabled ||
481       st->state.blend->blend_enable ||
482       st->state.blend->logicop_enable ||
483       st->state.depth_stencil->depth.enabled)
484      /* XXX more checks */
485      return GL_TRUE;
486   else
487      return GL_FALSE;
488}
489
490
491/**
492 * Check if any pixel transfer ops are enabled.
493 * XXX probably move this to a re-usable place.
494 */
495static GLboolean
496any_pixel_transfer_ops(const struct st_context *st)
497{
498   if (st->ctx->Pixel.RedScale != 1.0 ||
499       st->ctx->Pixel.RedBias != 0.0 ||
500       st->ctx->Pixel.GreenScale != 1.0 ||
501       st->ctx->Pixel.GreenBias != 0.0 ||
502       st->ctx->Pixel.BlueScale != 1.0 ||
503       st->ctx->Pixel.BlueBias != 0.0 ||
504       st->ctx->Pixel.AlphaScale != 1.0 ||
505       st->ctx->Pixel.AlphaBias != 0.0 ||
506       st->ctx->Pixel.MapColorFlag)
507      /* XXX more checks */
508      return GL_TRUE;
509   else
510      return GL_FALSE;
511}
512
513
514/**
515 * Draw image with a blit, or other non-textured quad method.
516 */
517static void
518draw_blit(struct st_context *st,
519          GLsizei width, GLsizei height,
520          GLenum format, GLenum type, const GLvoid *pixels)
521{
522
523
524}
525
526
527/**
528 * Called via ctx->Driver.DrawPixels()
529 */
530static void
531st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
532              GLenum format, GLenum type,
533              const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels)
534{
535   struct st_context *st = ctx->st;
536   struct pipe_surface *ps;
537   GLuint bufferFormat;
538
539   st_validate_state(st);
540
541   if (format == GL_DEPTH_COMPONENT) {
542      ps = st->state.framebuffer.zbuf;
543   }
544   else if (format == GL_STENCIL_INDEX) {
545      ps = st->state.framebuffer.sbuf;
546   }
547   else {
548      ps = st->state.framebuffer.cbufs[0];
549   }
550
551   bufferFormat = ps->format;
552
553   if (any_fragment_ops(st) ||
554       any_pixel_transfer_ops(st) ||
555       !compatible_formats(format, type, ps->format)) {
556      /* textured quad */
557      draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2], width, height,
558                         format, type, unpack, pixels);
559   }
560   else {
561      /* blit */
562      draw_blit(st, width, height, format, type, pixels);
563   }
564}
565
566
567static void
568st_Bitmap(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
569          const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap )
570{
571   struct st_context *st = ctx->st;
572
573   st_validate_state(st);
574
575   fprintf(stderr, "st_Bitmap not implemented yet\n");
576   /* XXX to do */
577}
578
579
580static void
581st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
582              GLsizei width, GLsizei height,
583              GLint dstx, GLint dsty, GLenum type)
584{
585   struct st_context *st = ctx->st;
586
587   st_validate_state(st);
588
589   fprintf(stderr, "st_CopyPixels not implemented yet\n");
590   /* XXX to do */
591}
592
593
594
595void st_init_drawpixels_functions(struct dd_function_table *functions)
596{
597   functions->DrawPixels = st_DrawPixels;
598   functions->CopyPixels = st_CopyPixels;
599   functions->Bitmap = st_Bitmap;
600}
601