drawpix.c revision 19b05d5009f4b0e83118b351b7261bb914e33f2b
1/*
2 * Mesa 3-D graphics library
3 * Version:  6.5
4 *
5 * Copyright (C) 1999-2006  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 (ctx->NewState) {
153      _mesa_update_state(ctx);
154   }
155
156   if (error_check_format_type(ctx, format, type, GL_TRUE)) {
157      /* found an error */
158      return;
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->NewState) {
203      _mesa_update_state(ctx);
204   }
205
206   if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) {
207      _mesa_error(ctx, GL_INVALID_OPERATION,
208                  "glCopyPixels (invalid fragment program)");
209      return;
210   }
211
212   if (width < 0 || height < 0) {
213      _mesa_error(ctx, GL_INVALID_VALUE, "glCopyPixels(width or height < 0)");
214      return;
215   }
216
217   switch (type) {
218   case GL_COLOR:
219      /* OK */
220      break;
221   case GL_DEPTH:
222      if (ctx->DrawBuffer->Visual.depthBits == 0 ||
223          ctx->ReadBuffer->Visual.depthBits == 0) {
224         _mesa_error(ctx, GL_INVALID_OPERATION,
225                     "glCopyPixels(no depth buffer)");
226         return;
227      }
228      break;
229   case GL_STENCIL:
230      if (ctx->DrawBuffer->Visual.stencilBits == 0 ||
231          ctx->ReadBuffer->Visual.stencilBits == 0) {
232         _mesa_error(ctx, GL_INVALID_OPERATION,
233                     "glCopyPixels(no stencil buffer)");
234         return;
235      }
236      break;
237   case GL_DEPTH_STENCIL_EXT:
238      if (!ctx->Extensions.EXT_packed_depth_stencil) {
239         _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels");
240         return;
241      }
242      if (ctx->DrawBuffer->Visual.depthBits == 0 ||
243          ctx->ReadBuffer->Visual.depthBits == 0 ||
244          ctx->DrawBuffer->Visual.stencilBits == 0 ||
245          ctx->ReadBuffer->Visual.stencilBits == 0) {
246         _mesa_error(ctx, GL_INVALID_OPERATION,
247                     "glCopyPixels(no depth or stencil buffer)");
248         return;
249      }
250      break;
251   default:
252      _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels");
253      return;
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 (ctx->NewState)
308      _mesa_update_state(ctx);
309
310   if (error_check_format_type(ctx, format, type, GL_FALSE)) {
311      /* found an error */
312      return;
313   }
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      if (bitmap) {
367         /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */
368         GLint x = IFLOOR(ctx->Current.RasterPos[0] - xorig);
369         GLint y = IFLOOR(ctx->Current.RasterPos[1] - yorig);
370         ctx->Driver.Bitmap( ctx, x, y, width, height, &ctx->Unpack, bitmap );
371      }
372   }
373#if _HAVE_FULL_GL
374   else if (ctx->RenderMode == GL_FEEDBACK) {
375      FLUSH_CURRENT(ctx, 0);
376      FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN );
377      _mesa_feedback_vertex( ctx,
378                             ctx->Current.RasterPos,
379                             ctx->Current.RasterColor,
380                             ctx->Current.RasterIndex,
381                             ctx->Current.RasterTexCoords[0] );
382   }
383   else {
384      ASSERT(ctx->RenderMode == GL_SELECT);
385      /* Do nothing.  See OpenGL Spec, Appendix B, Corollary 6. */
386   }
387#endif
388
389   /* update raster position */
390   ctx->Current.RasterPos[0] += xmove;
391   ctx->Current.RasterPos[1] += ymove;
392}
393
394
395
396#if 0  /* experimental */
397/*
398 * Execute glDrawDepthPixelsMESA().  This function accepts both a color
399 * image and depth (Z) image.  Rasterization produces fragments with
400 * color and Z taken from these images.  This function is intended for
401 * Z-compositing.  Normally, this operation requires two glDrawPixels
402 * calls with stencil testing.
403 */
404void GLAPIENTRY
405_mesa_DrawDepthPixelsMESA( GLsizei width, GLsizei height,
406                           GLenum colorFormat, GLenum colorType,
407                           const GLvoid *colors,
408                           GLenum depthType, const GLvoid *depths )
409{
410   GET_CURRENT_CONTEXT(ctx);
411   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
412
413   if (width < 0 || height < 0) {
414      _mesa_error( ctx, GL_INVALID_VALUE,
415                   "glDrawDepthPixelsMESA(width or height < 0" );
416      return;
417   }
418
419   if (!ctx->Current.RasterPosValid) {
420      return;
421   }
422
423   if (ctx->NewState) {
424      _mesa_update_state(ctx);
425   }
426
427   if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
428      _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
429                  "glDrawDepthPixelsMESA(incomplete framebuffer)");
430      return;
431   }
432
433   if (ctx->RenderMode == GL_RENDER) {
434      /* Round, to satisfy conformance tests (matches SGI's OpenGL) */
435      GLint x = IROUND(ctx->Current.RasterPos[0]);
436      GLint y = IROUND(ctx->Current.RasterPos[1]);
437      ctx->Driver.DrawDepthPixelsMESA(ctx, x, y, width, height,
438                                      colorFormat, colorType, colors,
439                                      depthType, depths, &ctx->Unpack);
440   }
441   else if (ctx->RenderMode == GL_FEEDBACK) {
442      /* Feedback the current raster pos info */
443      FLUSH_CURRENT( ctx, 0 );
444      FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN );
445      _mesa_feedback_vertex( ctx,
446                             ctx->Current.RasterPos,
447                             ctx->Current.RasterColor,
448                             ctx->Current.RasterIndex,
449                             ctx->Current.RasterTexCoords[0] );
450   }
451   else {
452      ASSERT(ctx->RenderMode == GL_SELECT);
453      /* Do nothing.  See OpenGL Spec, Appendix B, Corollary 6. */
454   }
455}
456
457#endif
458