readpix.c revision c1f859d4
1/*
2 * Mesa 3-D graphics library
3 * Version:  7.1
4 *
5 * Copyright (C) 1999-2008  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 "bufferobj.h"
28#include "context.h"
29#include "readpix.h"
30#include "framebuffer.h"
31#include "image.h"
32#include "state.h"
33
34
35/**
36 * Do error checking of the format/type parameters to glReadPixels and
37 * glDrawPixels.
38 * \param drawing if GL_TRUE do checking for DrawPixels, else do checking
39 *                for ReadPixels.
40 * \return GL_TRUE if error detected, GL_FALSE if no errors
41 */
42GLboolean
43_mesa_error_check_format_type(GLcontext *ctx, GLenum format, GLenum type,
44                              GLboolean drawing)
45{
46   const char *readDraw = drawing ? "Draw" : "Read";
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      if (!drawing && !_mesa_dest_buffer_exists(ctx, GL_COLOR)) {
82         _mesa_error(ctx, GL_INVALID_OPERATION,
83                     "glReadPixels(no color buffer)");
84         return GL_TRUE;
85      }
86      break;
87   case GL_COLOR_INDEX:
88      if (!drawing && ctx->Visual.rgbMode) {
89         _mesa_error(ctx, GL_INVALID_OPERATION,
90                    "glReadPixels(reading color index format from RGB buffer)");
91         return GL_TRUE;
92      }
93      if (!drawing && !_mesa_dest_buffer_exists(ctx, GL_COLOR)) {
94         _mesa_error(ctx, GL_INVALID_OPERATION,
95                     "glReadPixels(no color buffer)");
96         return GL_TRUE;
97      }
98      break;
99   case GL_STENCIL_INDEX:
100      if ((drawing && !_mesa_dest_buffer_exists(ctx, format)) ||
101          (!drawing && !_mesa_source_buffer_exists(ctx, format))) {
102         _mesa_error(ctx, GL_INVALID_OPERATION,
103                     "gl%sPixels(no stencil buffer)", readDraw);
104         return GL_TRUE;
105      }
106      break;
107   case GL_DEPTH_COMPONENT:
108      if ((drawing && !_mesa_dest_buffer_exists(ctx, format))) {
109         _mesa_error(ctx, GL_INVALID_OPERATION,
110                     "gl%sPixels(no depth buffer)", readDraw);
111         return GL_TRUE;
112      }
113      break;
114   case GL_DEPTH_STENCIL_EXT:
115      if (!ctx->Extensions.EXT_packed_depth_stencil ||
116          type != GL_UNSIGNED_INT_24_8_EXT) {
117         _mesa_error(ctx, GL_INVALID_ENUM, "gl%sPixels(type)", readDraw);
118         return GL_TRUE;
119      }
120      if ((drawing && !_mesa_dest_buffer_exists(ctx, format)) ||
121          (!drawing && !_mesa_source_buffer_exists(ctx, format))) {
122         _mesa_error(ctx, GL_INVALID_OPERATION,
123                     "gl%sPixels(no depth or stencil buffer)", readDraw);
124         return GL_TRUE;
125      }
126      break;
127   default:
128      /* this should have been caught in _mesa_is_legal_format_type() */
129      _mesa_problem(ctx, "unexpected format in _mesa_%sPixels", readDraw);
130      return GL_TRUE;
131   }
132
133   /* no errors */
134   return GL_FALSE;
135}
136
137
138
139void GLAPIENTRY
140_mesa_ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height,
141		  GLenum format, GLenum type, GLvoid *pixels )
142{
143   GET_CURRENT_CONTEXT(ctx);
144   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
145
146   FLUSH_CURRENT(ctx, 0);
147
148   if (width < 0 || height < 0) {
149      _mesa_error( ctx, GL_INVALID_VALUE,
150                   "glReadPixels(width=%d height=%d)", width, height );
151      return;
152   }
153
154   if (ctx->NewState)
155      _mesa_update_state(ctx);
156
157   if (_mesa_error_check_format_type(ctx, format, type, GL_FALSE)) {
158      /* found an error */
159      return;
160   }
161
162   if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
163      _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
164                  "glReadPixels(incomplete framebuffer)" );
165      return;
166   }
167
168   if (!_mesa_source_buffer_exists(ctx, format)) {
169      _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)");
170      return;
171   }
172
173   if (width == 0 || height == 0)
174      return; /* nothing to do */
175
176   if (ctx->Pack.BufferObj->Name) {
177      if (!_mesa_validate_pbo_access(2, &ctx->Pack, width, height, 1,
178                                     format, type, pixels)) {
179         _mesa_error(ctx, GL_INVALID_OPERATION,
180                     "glReadPixels(invalid PBO access)");
181         return;
182      }
183
184      if (ctx->Pack.BufferObj->Pointer) {
185         /* buffer is mapped - that's an error */
186         _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(PBO is mapped)");
187         return;
188      }
189   }
190
191   ctx->Driver.ReadPixels(ctx, x, y, width, height,
192			  format, type, &ctx->Pack, pixels);
193}
194