drawpix.c revision 547113c16cbef5db7753f4835ed7b7dd72e77380
1/*
2 * Mesa 3-D graphics library
3 * Version:  6.5
4 *
5 * Copyright (C) 1999-2005  Brian Paul   All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25#include "glheader.h"
26#include "imports.h"
27#include "context.h"
28#include "drawpix.h"
29#include "feedback.h"
30#include "image.h"
31#include "state.h"
32
33
34/**
35 * Do error checking of the format/type parameters to glReadPixels and
36 * glDrawPixels.
37 * \param drawing if GL_TRUE do checking for DrawPixels, else do checking
38 *                for ReadPixels.
39 * \return GL_TRUE if error detected, GL_FALSE if no errors
40 */
41static GLboolean
42error_check_format_type(GLcontext *ctx, GLenum format, GLenum type,
43                        GLboolean drawing)
44{
45   const char *readDraw = drawing ? "Draw" : "Read";
46   struct gl_framebuffer *fb = drawing ? ctx->DrawBuffer : ctx->ReadBuffer;
47
48   if (ctx->Extensions.EXT_packed_depth_stencil
49       && type == GL_UNSIGNED_INT_24_8_EXT
50       && format != GL_DEPTH_STENCIL_EXT) {
51      _mesa_error(ctx, GL_INVALID_OPERATION,
52                  "gl%sPixels(format is not GL_DEPTH_STENCIL_EXT)", readDraw);
53      return GL_TRUE;
54   }
55
56   /* basic combinations test */
57   if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
58      _mesa_error(ctx, GL_INVALID_ENUM,
59                  "gl%sPixels(format or type)", readDraw);
60      return GL_TRUE;
61   }
62
63   /* additional checks */
64   switch (format) {
65   case GL_RED:
66   case GL_GREEN:
67   case GL_BLUE:
68   case GL_ALPHA:
69   case GL_LUMINANCE:
70   case GL_LUMINANCE_ALPHA:
71   case GL_RGB:
72   case GL_BGR:
73   case GL_RGBA:
74   case GL_BGRA:
75   case GL_ABGR_EXT:
76      if (drawing && !ctx->Visual.rgbMode) {
77         _mesa_error(ctx, GL_INVALID_OPERATION,
78                   "glDrawPixels(drawing RGB pixels into color index buffer)");
79         return GL_TRUE;
80      }
81      break;
82   case GL_COLOR_INDEX:
83      if (!drawing && ctx->Visual.rgbMode) {
84         _mesa_error(ctx, GL_INVALID_OPERATION,
85                    "glReadPixels(reading color index format from RGB buffer");
86         return GL_TRUE;
87      }
88      break;
89   case GL_STENCIL_INDEX:
90      if (fb->Visual.stencilBits == 0) {
91         _mesa_error(ctx, GL_INVALID_OPERATION,
92                     "gl%sPixels(no stencil buffer)", readDraw);
93         return GL_TRUE;
94      }
95      break;
96   case GL_DEPTH_COMPONENT:
97      if (fb->Visual.depthBits == 0) {
98         _mesa_error(ctx, GL_INVALID_OPERATION,
99                     "gl%sPixels(no depth buffer)", readDraw);
100         return GL_TRUE;
101      }
102      break;
103   case GL_DEPTH_STENCIL_EXT:
104      if (!ctx->Extensions.EXT_packed_depth_stencil ||
105          type != GL_UNSIGNED_INT_24_8_EXT) {
106         _mesa_error(ctx, GL_INVALID_ENUM, "gl%sPixels(type)", readDraw);
107         return GL_TRUE;
108      }
109      if (fb->Visual.depthBits == 0 || fb->Visual.stencilBits == 0) {
110         _mesa_error(ctx, GL_INVALID_OPERATION,
111                     "gl%sPixels(no depth or stencil buffer)", readDraw);
112         return GL_TRUE;
113      }
114      ASSERT(fb->Attachment[BUFFER_DEPTH].Renderbuffer);
115      ASSERT(fb->Attachment[BUFFER_STENCIL].Renderbuffer);
116      break;
117   default:
118      /* this should have been caught in _mesa_is_legal_format_type() */
119      _mesa_problem(ctx, "unexpected format in _mesa_%sPixels", readDraw);
120      return GL_TRUE;
121   }
122
123   /* no errors */
124   return GL_FALSE;
125}
126
127
128
129#if _HAVE_FULL_GL
130
131/*
132 * Execute glDrawPixels
133 */
134void GLAPIENTRY
135_mesa_DrawPixels( GLsizei width, GLsizei height,
136                  GLenum format, GLenum type, const GLvoid *pixels )
137{
138   GET_CURRENT_CONTEXT(ctx);
139   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
140
141   if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) {
142      _mesa_error(ctx, GL_INVALID_OPERATION,
143                  "glDrawPixels (invalid fragment program)");
144      return;
145   }
146
147   if (width < 0 || height < 0) {
148      _mesa_error( ctx, GL_INVALID_VALUE, "glDrawPixels(width or height < 0" );
149      return;
150   }
151
152   if (error_check_format_type(ctx, format, type, GL_TRUE)) {
153      /* found an error */
154      return;
155   }
156
157   if (ctx->NewState) {
158      _mesa_update_state(ctx);
159   }
160
161   if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
162      _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
163                  "glDrawPixels(incomplete framebuffer)" );
164      return;
165   }
166
167   if (!ctx->Current.RasterPosValid) {
168      return;
169   }
170
171   if (ctx->RenderMode == GL_RENDER) {
172      /* Round, to satisfy conformance tests (matches SGI's OpenGL) */
173      GLint x = IROUND(ctx->Current.RasterPos[0]);
174      GLint y = IROUND(ctx->Current.RasterPos[1]);
175      ctx->Driver.DrawPixels(ctx, x, y, width, height, format, type,
176			     &ctx->Unpack, pixels);
177   }
178   else if (ctx->RenderMode == GL_FEEDBACK) {
179      /* Feedback the current raster pos info */
180      FLUSH_CURRENT( ctx, 0 );
181      FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN );
182      _mesa_feedback_vertex( ctx,
183                             ctx->Current.RasterPos,
184                             ctx->Current.RasterColor,
185                             ctx->Current.RasterIndex,
186                             ctx->Current.RasterTexCoords[0] );
187   }
188   else {
189      ASSERT(ctx->RenderMode == GL_SELECT);
190      /* Do nothing.  See OpenGL Spec, Appendix B, Corollary 6. */
191   }
192}
193
194
195void GLAPIENTRY
196_mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height,
197                  GLenum type )
198{
199   GET_CURRENT_CONTEXT(ctx);
200   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
201
202   if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) {
203      _mesa_error(ctx, GL_INVALID_OPERATION,
204                  "glCopyPixels (invalid fragment program)");
205      return;
206   }
207
208   if (width < 0 || height < 0) {
209      _mesa_error(ctx, GL_INVALID_VALUE, "glCopyPixels(width or height < 0)");
210      return;
211   }
212
213   switch (type) {
214   case GL_COLOR:
215      /* OK */
216      break;
217   case GL_DEPTH:
218      if (ctx->DrawBuffer->Visual.depthBits == 0 ||
219          ctx->ReadBuffer->Visual.depthBits == 0) {
220         _mesa_error(ctx, GL_INVALID_OPERATION,
221                     "glCopyPixels(no depth buffer)");
222         return;
223      }
224      break;
225   case GL_STENCIL:
226      if (ctx->DrawBuffer->Visual.stencilBits == 0 ||
227          ctx->ReadBuffer->Visual.stencilBits == 0) {
228         _mesa_error(ctx, GL_INVALID_OPERATION,
229                     "glCopyPixels(no stencil buffer)");
230         return;
231      }
232      break;
233   case GL_DEPTH_STENCIL_EXT:
234      if (!ctx->Extensions.EXT_packed_depth_stencil) {
235         _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels");
236         return;
237      }
238      if (ctx->DrawBuffer->Visual.depthBits == 0 ||
239          ctx->ReadBuffer->Visual.depthBits == 0 ||
240          ctx->DrawBuffer->Visual.stencilBits == 0 ||
241          ctx->ReadBuffer->Visual.stencilBits == 0) {
242         _mesa_error(ctx, GL_INVALID_OPERATION,
243                     "glCopyPixels(no depth or stencil buffer)");
244         return;
245      }
246      break;
247   default:
248      _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels");
249      return;
250   }
251
252   if (ctx->NewState) {
253      _mesa_update_state(ctx);
254   }
255
256   if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
257       ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
258      _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
259                  "glCopyPixels(incomplete framebuffer)" );
260      return;
261   }
262
263   if (!ctx->Current.RasterPosValid) {
264      return;
265   }
266
267   if (ctx->RenderMode == GL_RENDER) {
268      /* Round to satisfy conformance tests (matches SGI's OpenGL) */
269      GLint destx = IROUND(ctx->Current.RasterPos[0]);
270      GLint desty = IROUND(ctx->Current.RasterPos[1]);
271      ctx->Driver.CopyPixels( ctx, srcx, srcy, width, height, destx, desty,
272			      type );
273   }
274   else if (ctx->RenderMode == GL_FEEDBACK) {
275      FLUSH_CURRENT( ctx, 0 );
276      FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_COPY_PIXEL_TOKEN );
277      _mesa_feedback_vertex( ctx,
278                             ctx->Current.RasterPos,
279                             ctx->Current.RasterColor,
280                             ctx->Current.RasterIndex,
281                             ctx->Current.RasterTexCoords[0] );
282   }
283   else {
284      ASSERT(ctx->RenderMode == GL_SELECT);
285      /* Do nothing.  See OpenGL Spec, Appendix B, Corollary 6. */
286   }
287}
288
289#endif /* _HAVE_FULL_GL */
290
291
292
293void GLAPIENTRY
294_mesa_ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height,
295		  GLenum format, GLenum type, GLvoid *pixels )
296{
297   GET_CURRENT_CONTEXT(ctx);
298   const struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
299   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
300
301   if (width < 0 || height < 0) {
302      _mesa_error( ctx, GL_INVALID_VALUE,
303                   "glReadPixels(width=%d height=%d)", width, height );
304      return;
305   }
306
307   if (error_check_format_type(ctx, format, type, GL_FALSE)) {
308      /* found an error */
309      return;
310   }
311
312   if (ctx->NewState)
313      _mesa_update_state(ctx);
314
315   if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
316      _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
317                  "glReadPixels(incomplete framebuffer)" );
318      return;
319   }
320
321   if (!rb) {
322      _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)");
323      return;
324   }
325
326   ctx->Driver.ReadPixels(ctx, x, y, width, height,
327			  format, type, &ctx->Pack, pixels);
328}
329
330
331
332void GLAPIENTRY
333_mesa_Bitmap( GLsizei width, GLsizei height,
334              GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove,
335              const GLubyte *bitmap )
336{
337   GET_CURRENT_CONTEXT(ctx);
338   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
339
340   if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) {
341      _mesa_error(ctx, GL_INVALID_OPERATION,
342                  "glBitmap (invalid fragment program)");
343      return;
344   }
345
346   if (width < 0 || height < 0) {
347      _mesa_error( ctx, GL_INVALID_VALUE, "glBitmap(width or height < 0)" );
348      return;
349   }
350
351   if (!ctx->Current.RasterPosValid) {
352      return;    /* do nothing */
353   }
354
355   if (ctx->NewState) {
356      _mesa_update_state(ctx);
357   }
358
359   if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
360      _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
361                  "glBitmap(incomplete framebuffer)");
362      return;
363   }
364
365   if (ctx->RenderMode == GL_RENDER) {
366      /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */
367      GLint x = IFLOOR(ctx->Current.RasterPos[0] - xorig);
368      GLint y = IFLOOR(ctx->Current.RasterPos[1] - yorig);
369      ctx->Driver.Bitmap( ctx, x, y, width, height, &ctx->Unpack, bitmap );
370   }
371#if _HAVE_FULL_GL
372   else if (ctx->RenderMode == GL_FEEDBACK) {
373      FLUSH_CURRENT(ctx, 0);
374      FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN );
375      _mesa_feedback_vertex( ctx,
376                             ctx->Current.RasterPos,
377                             ctx->Current.RasterColor,
378                             ctx->Current.RasterIndex,
379                             ctx->Current.RasterTexCoords[0] );
380   }
381   else {
382      ASSERT(ctx->RenderMode == GL_SELECT);
383      /* Do nothing.  See OpenGL Spec, Appendix B, Corollary 6. */
384   }
385#endif
386
387   /* update raster position */
388   ctx->Current.RasterPos[0] += xmove;
389   ctx->Current.RasterPos[1] += ymove;
390}
391
392
393
394#if 0  /* experimental */
395/*
396 * Execute glDrawDepthPixelsMESA().  This function accepts both a color
397 * image and depth (Z) image.  Rasterization produces fragments with
398 * color and Z taken from these images.  This function is intended for
399 * Z-compositing.  Normally, this operation requires two glDrawPixels
400 * calls with stencil testing.
401 */
402void GLAPIENTRY
403_mesa_DrawDepthPixelsMESA( GLsizei width, GLsizei height,
404                           GLenum colorFormat, GLenum colorType,
405                           const GLvoid *colors,
406                           GLenum depthType, const GLvoid *depths )
407{
408   GET_CURRENT_CONTEXT(ctx);
409   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
410
411   if (width < 0 || height < 0) {
412      _mesa_error( ctx, GL_INVALID_VALUE,
413                   "glDrawDepthPixelsMESA(width or height < 0" );
414      return;
415   }
416
417   if (!ctx->Current.RasterPosValid) {
418      return;
419   }
420
421   if (ctx->NewState) {
422      _mesa_update_state(ctx);
423   }
424
425   if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
426      _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
427                  "glDrawDepthPixelsMESA(incomplete framebuffer)");
428      return;
429   }
430
431   if (ctx->RenderMode == GL_RENDER) {
432      /* Round, to satisfy conformance tests (matches SGI's OpenGL) */
433      GLint x = IROUND(ctx->Current.RasterPos[0]);
434      GLint y = IROUND(ctx->Current.RasterPos[1]);
435      ctx->Driver.DrawDepthPixelsMESA(ctx, x, y, width, height,
436                                      colorFormat, colorType, colors,
437                                      depthType, depths, &ctx->Unpack);
438   }
439   else if (ctx->RenderMode == GL_FEEDBACK) {
440      /* Feedback the current raster pos info */
441      FLUSH_CURRENT( ctx, 0 );
442      FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN );
443      _mesa_feedback_vertex( ctx,
444                             ctx->Current.RasterPos,
445                             ctx->Current.RasterColor,
446                             ctx->Current.RasterIndex,
447                             ctx->Current.RasterTexCoords[0] );
448   }
449   else {
450      ASSERT(ctx->RenderMode == GL_SELECT);
451      /* Do nothing.  See OpenGL Spec, Appendix B, Corollary 6. */
452   }
453}
454
455#endif
456