drawpix.c revision 1ad7b99925e044f82e635f746c1ef2df77f69ac9
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
47   /* basic combinations test */
48   if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
49      _mesa_error(ctx, GL_INVALID_ENUM,
50                  "gl%sPixels(format or type)", readDraw);
51      return GL_TRUE;
52   }
53
54   /* additional checks */
55   switch (format) {
56   case GL_RED:
57   case GL_GREEN:
58   case GL_BLUE:
59   case GL_ALPHA:
60   case GL_LUMINANCE:
61   case GL_LUMINANCE_ALPHA:
62   case GL_RGB:
63   case GL_BGR:
64   case GL_RGBA:
65   case GL_BGRA:
66   case GL_ABGR_EXT:
67      if (drawing && !ctx->Visual.rgbMode) {
68         _mesa_error(ctx, GL_INVALID_OPERATION,
69                   "glDrawPixels(drawing RGB pixels into color index buffer)");
70         return GL_TRUE;
71      }
72      break;
73   case GL_COLOR_INDEX:
74      if (!drawing && ctx->Visual.rgbMode) {
75         _mesa_error(ctx, GL_INVALID_OPERATION,
76                    "glReadPixels(reading color index format from RGB buffer");
77         return GL_TRUE;
78      }
79      break;
80   case GL_STENCIL_INDEX:
81      if (ctx->DrawBuffer->Visual.stencilBits == 0) {
82         _mesa_error(ctx, GL_INVALID_OPERATION,
83                     "gl%sPixels(no stencil buffer)", readDraw);
84         return GL_TRUE;
85      }
86      break;
87   case GL_DEPTH_COMPONENT:
88      if (ctx->DrawBuffer->Visual.depthBits == 0) {
89         _mesa_error(ctx, GL_INVALID_OPERATION,
90                     "gl%sPixels(no depth buffer)", readDraw);
91         return GL_TRUE;
92      }
93      break;
94   case GL_DEPTH_STENCIL_EXT:
95      if (!ctx->Extensions.EXT_packed_depth_stencil ||
96          type != GL_UNSIGNED_INT_24_8_EXT) {
97         _mesa_error(ctx, GL_INVALID_ENUM, "gl%sPixels(type)", readDraw);
98         return GL_TRUE;
99      }
100      if (ctx->DrawBuffer->Visual.depthBits == 0 ||
101          ctx->ReadBuffer->Visual.depthBits == 0 ||
102          ctx->DrawBuffer->Visual.stencilBits == 0 ||
103          ctx->ReadBuffer->Visual.stencilBits == 0) {
104         _mesa_error(ctx, GL_INVALID_OPERATION,
105                     "gl%sPixels(no depth or stencil buffer)", readDraw);
106         return GL_TRUE;
107      }
108      break;
109   default:
110      /* this should have been caught in _mesa_is_legal_format_type() */
111      _mesa_problem(ctx, "unexpected format in _mesa_%sPixels", readDraw);
112      return GL_TRUE;
113   }
114
115   /* XXX might have to move this to the top of the function */
116   if (type == GL_UNSIGNED_INT_24_8_EXT && format != GL_DEPTH_STENCIL_EXT) {
117      _mesa_error(ctx, GL_INVALID_OPERATION,
118                  "gl%sPixels(format is not GL_DEPTH_STENCIL_EXT)", readDraw);
119      return GL_TRUE;
120   }
121
122   /* no errors */
123   return GL_FALSE;
124}
125
126
127
128#if _HAVE_FULL_GL
129
130/*
131 * Execute glDrawPixels
132 */
133void GLAPIENTRY
134_mesa_DrawPixels( GLsizei width, GLsizei height,
135                  GLenum format, GLenum type, const GLvoid *pixels )
136{
137   GET_CURRENT_CONTEXT(ctx);
138   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
139
140   if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) {
141      _mesa_error(ctx, GL_INVALID_OPERATION,
142                  "glDrawPixels (invalid fragment program)");
143      return;
144   }
145
146   if (width < 0 || height < 0) {
147      _mesa_error( ctx, GL_INVALID_VALUE, "glDrawPixels(width or height < 0" );
148      return;
149   }
150
151   if (error_check_format_type(ctx, format, type, GL_TRUE)) {
152      /* found an error */
153      return;
154   }
155
156   if (!ctx->Current.RasterPosValid) {
157      return; /* not an error */
158   }
159
160   if (ctx->NewState) {
161      _mesa_update_state(ctx);
162   }
163
164   if (ctx->RenderMode == GL_RENDER) {
165      /* Round, to satisfy conformance tests (matches SGI's OpenGL) */
166      GLint x = IROUND(ctx->Current.RasterPos[0]);
167      GLint y = IROUND(ctx->Current.RasterPos[1]);
168      ctx->Driver.DrawPixels(ctx, x, y, width, height, format, type,
169			     &ctx->Unpack, pixels);
170   }
171   else if (ctx->RenderMode == GL_FEEDBACK) {
172      /* Feedback the current raster pos info */
173      FLUSH_CURRENT( ctx, 0 );
174      FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN );
175      _mesa_feedback_vertex( ctx,
176                             ctx->Current.RasterPos,
177                             ctx->Current.RasterColor,
178                             ctx->Current.RasterIndex,
179                             ctx->Current.RasterTexCoords[0] );
180   }
181   else {
182      ASSERT(ctx->RenderMode == GL_SELECT);
183      /* Do nothing.  See OpenGL Spec, Appendix B, Corollary 6. */
184   }
185}
186
187
188void GLAPIENTRY
189_mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height,
190                  GLenum type )
191{
192   GET_CURRENT_CONTEXT(ctx);
193   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
194
195   if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) {
196      _mesa_error(ctx, GL_INVALID_OPERATION,
197                  "glCopyPixels (invalid fragment program)");
198      return;
199   }
200
201   if (width < 0 || height < 0) {
202      _mesa_error(ctx, GL_INVALID_VALUE, "glCopyPixels(width or height < 0)");
203      return;
204   }
205
206   switch (type) {
207   case GL_COLOR:
208      /* OK */
209      break;
210   case GL_DEPTH:
211      if (ctx->DrawBuffer->Visual.depthBits == 0 ||
212          ctx->ReadBuffer->Visual.depthBits == 0) {
213         _mesa_error(ctx, GL_INVALID_OPERATION,
214                     "glCopyPixels(no depth buffer)");
215         return;
216      }
217      break;
218   case GL_STENCIL:
219      if (ctx->DrawBuffer->Visual.stencilBits == 0 ||
220          ctx->ReadBuffer->Visual.stencilBits == 0) {
221         _mesa_error(ctx, GL_INVALID_OPERATION,
222                     "glCopyPixels(no stencil buffer)");
223         return;
224      }
225      break;
226   case GL_DEPTH_STENCIL_EXT:
227      if (!ctx->Extensions.EXT_packed_depth_stencil) {
228         _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels");
229         return;
230      }
231      if (ctx->DrawBuffer->Visual.depthBits == 0 ||
232          ctx->ReadBuffer->Visual.depthBits == 0 ||
233          ctx->DrawBuffer->Visual.stencilBits == 0 ||
234          ctx->ReadBuffer->Visual.stencilBits == 0) {
235         _mesa_error(ctx, GL_INVALID_OPERATION,
236                     "glCopyPixels(no depth or stencil buffer)");
237         return;
238      }
239      break;
240   default:
241      _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels");
242      return;
243   }
244
245   if (ctx->NewState) {
246      _mesa_update_state(ctx);
247   }
248
249   if (!ctx->Current.RasterPosValid) {
250      return;
251   }
252
253   if (ctx->RenderMode == GL_RENDER) {
254      /* Round to satisfy conformance tests (matches SGI's OpenGL) */
255      GLint destx = IROUND(ctx->Current.RasterPos[0]);
256      GLint desty = IROUND(ctx->Current.RasterPos[1]);
257      ctx->Driver.CopyPixels( ctx, srcx, srcy, width, height, destx, desty,
258			      type );
259   }
260   else if (ctx->RenderMode == GL_FEEDBACK) {
261      FLUSH_CURRENT( ctx, 0 );
262      FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_COPY_PIXEL_TOKEN );
263      _mesa_feedback_vertex( ctx,
264                             ctx->Current.RasterPos,
265                             ctx->Current.RasterColor,
266                             ctx->Current.RasterIndex,
267                             ctx->Current.RasterTexCoords[0] );
268   }
269   else {
270      ASSERT(ctx->RenderMode == GL_SELECT);
271      /* Do nothing.  See OpenGL Spec, Appendix B, Corollary 6. */
272   }
273}
274
275#endif /* _HAVE_FULL_GL */
276
277
278
279void GLAPIENTRY
280_mesa_ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height,
281		  GLenum format, GLenum type, GLvoid *pixels )
282{
283   GET_CURRENT_CONTEXT(ctx);
284   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
285
286   if (width < 0 || height < 0) {
287      _mesa_error( ctx, GL_INVALID_VALUE,
288                   "glReadPixels(width=%d height=%d)", width, height );
289      return;
290   }
291
292   if (error_check_format_type(ctx, format, type, GL_FALSE)) {
293      /* found an error */
294      return;
295   }
296
297   if (ctx->NewState)
298      _mesa_update_state(ctx);
299
300   ctx->Driver.ReadPixels(ctx, x, y, width, height,
301			  format, type, &ctx->Pack, pixels);
302}
303
304
305
306void GLAPIENTRY
307_mesa_Bitmap( GLsizei width, GLsizei height,
308              GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove,
309              const GLubyte *bitmap )
310{
311   GET_CURRENT_CONTEXT(ctx);
312   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
313
314   if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) {
315      _mesa_error(ctx, GL_INVALID_OPERATION,
316                  "glBitmap (invalid fragment program)");
317      return;
318   }
319
320   if (width < 0 || height < 0) {
321      _mesa_error( ctx, GL_INVALID_VALUE, "glBitmap(width or height < 0)" );
322      return;
323   }
324
325   if (!ctx->Current.RasterPosValid) {
326      return;    /* do nothing */
327   }
328
329   if (ctx->NewState) {
330      _mesa_update_state(ctx);
331   }
332
333   if (ctx->RenderMode == GL_RENDER) {
334      /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */
335      GLint x = IFLOOR(ctx->Current.RasterPos[0] - xorig);
336      GLint y = IFLOOR(ctx->Current.RasterPos[1] - yorig);
337      ctx->Driver.Bitmap( ctx, x, y, width, height, &ctx->Unpack, bitmap );
338   }
339#if _HAVE_FULL_GL
340   else if (ctx->RenderMode == GL_FEEDBACK) {
341      FLUSH_CURRENT(ctx, 0);
342      FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN );
343      _mesa_feedback_vertex( ctx,
344                             ctx->Current.RasterPos,
345                             ctx->Current.RasterColor,
346                             ctx->Current.RasterIndex,
347                             ctx->Current.RasterTexCoords[0] );
348   }
349   else {
350      ASSERT(ctx->RenderMode == GL_SELECT);
351      /* Do nothing.  See OpenGL Spec, Appendix B, Corollary 6. */
352   }
353#endif
354
355   /* update raster position */
356   ctx->Current.RasterPos[0] += xmove;
357   ctx->Current.RasterPos[1] += ymove;
358}
359
360
361
362#if 0  /* experimental */
363/*
364 * Execute glDrawDepthPixelsMESA().  This function accepts both a color
365 * image and depth (Z) image.  Rasterization produces fragments with
366 * color and Z taken from these images.  This function is intended for
367 * Z-compositing.  Normally, this operation requires two glDrawPixels
368 * calls with stencil testing.
369 */
370void GLAPIENTRY
371_mesa_DrawDepthPixelsMESA( GLsizei width, GLsizei height,
372                           GLenum colorFormat, GLenum colorType,
373                           const GLvoid *colors,
374                           GLenum depthType, const GLvoid *depths )
375{
376   GET_CURRENT_CONTEXT(ctx);
377   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
378
379   if (width < 0 || height < 0) {
380      _mesa_error( ctx, GL_INVALID_VALUE,
381                   "glDrawDepthPixelsMESA(width or height < 0" );
382      return;
383   }
384
385   if (!ctx->Current.RasterPosValid) {
386      return;
387   }
388
389   if (ctx->NewState) {
390      _mesa_update_state(ctx);
391   }
392
393   if (ctx->RenderMode == GL_RENDER) {
394      /* Round, to satisfy conformance tests (matches SGI's OpenGL) */
395      GLint x = IROUND(ctx->Current.RasterPos[0]);
396      GLint y = IROUND(ctx->Current.RasterPos[1]);
397      ctx->Driver.DrawDepthPixelsMESA(ctx, x, y, width, height,
398                                      colorFormat, colorType, colors,
399                                      depthType, depths, &ctx->Unpack);
400   }
401   else if (ctx->RenderMode == GL_FEEDBACK) {
402      /* Feedback the current raster pos info */
403      FLUSH_CURRENT( ctx, 0 );
404      FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN );
405      _mesa_feedback_vertex( ctx,
406                             ctx->Current.RasterPos,
407                             ctx->Current.RasterColor,
408                             ctx->Current.RasterIndex,
409                             ctx->Current.RasterTexCoords[0] );
410   }
411   else {
412      ASSERT(ctx->RenderMode == GL_SELECT);
413      /* Do nothing.  See OpenGL Spec, Appendix B, Corollary 6. */
414   }
415}
416
417#endif
418