1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 1999-2008 Brian Paul 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 "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 #include "glheader.h"
26 #include "draw_validate.h"
27 #include "bufferobj.h"
28 #include "context.h"
29 #include "enums.h"
30 #include "feedback.h"
31 #include "framebuffer.h"
32 #include "image.h"
33 #include "pbo.h"
34 #include "pixel.h"
35 #include "state.h"
36 #include "glformats.h"
37 #include "fbobject.h"
38 #include "util/u_math.h"
39 #include "util/rounding.h"
40 #include "api_exec_decl.h"
41
42 #include "state_tracker/st_cb_bitmap.h"
43 #include "state_tracker/st_cb_drawpixels.h"
44
45 /*
46 * Execute glDrawPixels
47 */
48 void GLAPIENTRY
_mesa_DrawPixels(GLsizei width,GLsizei height,GLenum format,GLenum type,const GLvoid * pixels)49 _mesa_DrawPixels( GLsizei width, GLsizei height,
50 GLenum format, GLenum type, const GLvoid *pixels )
51 {
52 GLenum err;
53 GET_CURRENT_CONTEXT(ctx);
54
55 FLUSH_VERTICES(ctx, 0, 0);
56
57 if (MESA_VERBOSE & VERBOSE_API)
58 _mesa_debug(ctx, "glDrawPixels(%d, %d, %s, %s, %p) // to %s at %ld, %ld\n",
59 width, height,
60 _mesa_enum_to_string(format),
61 _mesa_enum_to_string(type),
62 pixels,
63 _mesa_enum_to_string(ctx->DrawBuffer->ColorDrawBuffer[0]),
64 lroundf(ctx->Current.RasterPos[0]),
65 lroundf(ctx->Current.RasterPos[1]));
66
67
68 if (width < 0 || height < 0) {
69 _mesa_error( ctx, GL_INVALID_VALUE, "glDrawPixels(width or height < 0)" );
70 return;
71 }
72
73 /* We're not using the current vertex program, and the driver may install
74 * its own. Note: this may dirty some state.
75 */
76 _mesa_set_vp_override(ctx, GL_TRUE);
77
78 _mesa_update_pixel(ctx);
79
80 if (ctx->NewState)
81 _mesa_update_state(ctx);
82
83 if (!ctx->DrawPixValid) {
84 _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels");
85 goto end;
86 }
87
88 /* GL 3.0 introduced a new restriction on glDrawPixels() over what was in
89 * GL_EXT_texture_integer. From section 3.7.4 ("Rasterization of Pixel
90 * Rectangles) on page 151 of the GL 3.0 specification:
91 *
92 * "If format contains integer components, as shown in table 3.6, an
93 * INVALID OPERATION error is generated."
94 *
95 * Since DrawPixels rendering would be merely undefined if not an error (due
96 * to a lack of defined mapping from integer data to gl_Color fragment shader
97 * input), NVIDIA's implementation also just returns this error despite
98 * exposing GL_EXT_texture_integer, just return an error regardless.
99 */
100 if (_mesa_is_enum_format_integer(format)) {
101 _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels(integer format)");
102 goto end;
103 }
104
105 err = _mesa_error_check_format_and_type(ctx, format, type);
106 if (err != GL_NO_ERROR) {
107 _mesa_error(ctx, err, "glDrawPixels(invalid format %s and/or type %s)",
108 _mesa_enum_to_string(format),
109 _mesa_enum_to_string(type));
110 goto end;
111 }
112
113 /* do special format-related checks */
114 switch (format) {
115 case GL_STENCIL_INDEX:
116 case GL_DEPTH_COMPONENT:
117 case GL_DEPTH_STENCIL_EXT:
118 /* these buffers must exist */
119 if (!_mesa_dest_buffer_exists(ctx, format)) {
120 _mesa_error(ctx, GL_INVALID_OPERATION,
121 "glDrawPixels(missing dest buffer)");
122 goto end;
123 }
124 break;
125 case GL_COLOR_INDEX:
126 if (ctx->PixelMaps.ItoR.Size == 0 ||
127 ctx->PixelMaps.ItoG.Size == 0 ||
128 ctx->PixelMaps.ItoB.Size == 0) {
129 _mesa_error(ctx, GL_INVALID_OPERATION,
130 "glDrawPixels(drawing color index pixels into RGB buffer)");
131 goto end;
132 }
133 break;
134 default:
135 /* for color formats it's not an error if the destination color
136 * buffer doesn't exist.
137 */
138 break;
139 }
140
141 if (ctx->RasterDiscard) {
142 goto end;
143 }
144
145 if (!ctx->Current.RasterPosValid) {
146 goto end; /* no-op, not an error */
147 }
148
149 if (ctx->RenderMode == GL_RENDER) {
150 if (width > 0 && height > 0) {
151 /* Round, to satisfy conformance tests (matches SGI's OpenGL) */
152 GLint x = lroundf(ctx->Current.RasterPos[0]);
153 GLint y = lroundf(ctx->Current.RasterPos[1]);
154
155 if (ctx->Unpack.BufferObj) {
156 /* unpack from PBO */
157 if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height,
158 1, format, type, INT_MAX, pixels)) {
159 _mesa_error(ctx, GL_INVALID_OPERATION,
160 "glDrawPixels(invalid PBO access)");
161 goto end;
162 }
163 if (_mesa_check_disallowed_mapping(ctx->Unpack.BufferObj)) {
164 /* buffer is mapped - that's an error */
165 _mesa_error(ctx, GL_INVALID_OPERATION,
166 "glDrawPixels(PBO is mapped)");
167 goto end;
168 }
169 }
170
171 st_DrawPixels(ctx, x, y, width, height, format, type,
172 &ctx->Unpack, pixels);
173 }
174 }
175 else if (ctx->RenderMode == GL_FEEDBACK) {
176 /* Feedback the current raster pos info */
177 FLUSH_CURRENT( ctx, 0 );
178 _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN );
179 _mesa_feedback_vertex( ctx,
180 ctx->Current.RasterPos,
181 ctx->Current.RasterColor,
182 ctx->Current.RasterTexCoords[0] );
183 }
184 else {
185 assert(ctx->RenderMode == GL_SELECT);
186 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */
187 }
188
189 end:
190 _mesa_set_vp_override(ctx, GL_FALSE);
191
192 if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
193 _mesa_flush(ctx);
194 }
195 }
196
197
198 void GLAPIENTRY
_mesa_CopyPixels(GLint srcx,GLint srcy,GLsizei width,GLsizei height,GLenum type)199 _mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height,
200 GLenum type )
201 {
202 GET_CURRENT_CONTEXT(ctx);
203
204 FLUSH_VERTICES(ctx, 0, 0);
205
206 if (MESA_VERBOSE & VERBOSE_API)
207 _mesa_debug(ctx,
208 "glCopyPixels(%d, %d, %d, %d, %s) // from %s to %s at %ld, %ld\n",
209 srcx, srcy, width, height,
210 _mesa_enum_to_string(type),
211 _mesa_enum_to_string(ctx->ReadBuffer->ColorReadBuffer),
212 _mesa_enum_to_string(ctx->DrawBuffer->ColorDrawBuffer[0]),
213 lroundf(ctx->Current.RasterPos[0]),
214 lroundf(ctx->Current.RasterPos[1]));
215
216 if (width < 0 || height < 0) {
217 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyPixels(width or height < 0)");
218 return;
219 }
220
221 /* Note: more detailed 'type' checking is done by the
222 * _mesa_source/dest_buffer_exists() calls below. That's where we
223 * check if the stencil buffer exists, etc.
224 */
225 if (type != GL_COLOR &&
226 type != GL_DEPTH &&
227 type != GL_STENCIL &&
228 type != GL_DEPTH_STENCIL &&
229 type != GL_DEPTH_STENCIL_TO_RGBA_NV &&
230 type != GL_DEPTH_STENCIL_TO_BGRA_NV) {
231 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels(type=%s)",
232 _mesa_enum_to_string(type));
233 return;
234 }
235
236 /* Return GL_INVALID_ENUM if the relevant extension is not enabled */
237 if ((type == GL_DEPTH_STENCIL_TO_RGBA_NV || type == GL_DEPTH_STENCIL_TO_BGRA_NV) &&
238 !ctx->Extensions.NV_copy_depth_to_color) {
239 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels(type=%s)",
240 _mesa_enum_to_string(type));
241 return;
242 }
243
244 /* We're not using the current vertex program, and the driver may install
245 * it's own. Note: this may dirty some state.
246 */
247 _mesa_set_vp_override(ctx, GL_TRUE);
248
249 _mesa_update_pixel(ctx);
250
251 if (ctx->NewState)
252 _mesa_update_state(ctx);
253
254 if (!ctx->DrawPixValid) {
255 _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyPixels");
256 goto end;
257 }
258
259 /* Check read buffer's status (draw buffer was already checked) */
260 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
261 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
262 "glCopyPixels(incomplete framebuffer)" );
263 goto end;
264 }
265
266 if (_mesa_is_user_fbo(ctx->ReadBuffer) &&
267 ctx->ReadBuffer->Visual.samples > 0) {
268 _mesa_error(ctx, GL_INVALID_OPERATION,
269 "glCopyPixels(multisample FBO)");
270 goto end;
271 }
272
273 if (!_mesa_source_buffer_exists(ctx, type) ||
274 !_mesa_dest_buffer_exists(ctx, type)) {
275 _mesa_error(ctx, GL_INVALID_OPERATION,
276 "glCopyPixels(missing source or dest buffer)");
277 goto end;
278 }
279
280 if (ctx->RasterDiscard) {
281 goto end;
282 }
283
284 if (!ctx->Current.RasterPosValid || width == 0 || height == 0) {
285 goto end; /* no-op, not an error */
286 }
287
288 if (ctx->RenderMode == GL_RENDER) {
289 /* Round to satisfy conformance tests (matches SGI's OpenGL) */
290 if (width > 0 && height > 0) {
291 GLint destx = lroundf(ctx->Current.RasterPos[0]);
292 GLint desty = lroundf(ctx->Current.RasterPos[1]);
293 st_CopyPixels( ctx, srcx, srcy, width, height, destx, desty,
294 type );
295 }
296 }
297 else if (ctx->RenderMode == GL_FEEDBACK) {
298 FLUSH_CURRENT( ctx, 0 );
299 _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_COPY_PIXEL_TOKEN );
300 _mesa_feedback_vertex( ctx,
301 ctx->Current.RasterPos,
302 ctx->Current.RasterColor,
303 ctx->Current.RasterTexCoords[0] );
304 }
305 else {
306 assert(ctx->RenderMode == GL_SELECT);
307 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */
308 }
309
310 end:
311 _mesa_set_vp_override(ctx, GL_FALSE);
312
313 if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
314 _mesa_flush(ctx);
315 }
316 }
317
318
319 void GLAPIENTRY
_mesa_Bitmap(GLsizei width,GLsizei height,GLfloat xorig,GLfloat yorig,GLfloat xmove,GLfloat ymove,const GLubyte * bitmap)320 _mesa_Bitmap( GLsizei width, GLsizei height,
321 GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove,
322 const GLubyte *bitmap )
323 {
324 GET_CURRENT_CONTEXT(ctx);
325
326 FLUSH_VERTICES(ctx, 0, 0);
327
328 if (width < 0 || height < 0) {
329 _mesa_error( ctx, GL_INVALID_VALUE, "glBitmap(width or height < 0)" );
330 return;
331 }
332
333 if (!ctx->Current.RasterPosValid) {
334 return; /* do nothing */
335 }
336
337 _mesa_update_pixel(ctx);
338
339 if (ctx->NewState)
340 _mesa_update_state(ctx);
341
342 if (!ctx->DrawPixValid) {
343 _mesa_error(ctx, GL_INVALID_OPERATION, "glBitmap");
344 return;
345 }
346
347 if (ctx->RasterDiscard)
348 return;
349
350 if (ctx->RenderMode == GL_RENDER) {
351 /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */
352 if (width > 0 && height > 0) {
353 const GLfloat epsilon = 0.0001F;
354 GLint x = util_ifloor(ctx->Current.RasterPos[0] + epsilon - xorig);
355 GLint y = util_ifloor(ctx->Current.RasterPos[1] + epsilon - yorig);
356
357 if (ctx->Unpack.BufferObj) {
358 /* unpack from PBO */
359 if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height,
360 1, GL_COLOR_INDEX, GL_BITMAP,
361 INT_MAX, (const GLvoid *) bitmap)) {
362 _mesa_error(ctx, GL_INVALID_OPERATION,
363 "glBitmap(invalid PBO access)");
364 return;
365 }
366 if (_mesa_check_disallowed_mapping(ctx->Unpack.BufferObj)) {
367 /* buffer is mapped - that's an error */
368 _mesa_error(ctx, GL_INVALID_OPERATION,
369 "glBitmap(PBO is mapped)");
370 return;
371 }
372 }
373
374 st_Bitmap( ctx, x, y, width, height, &ctx->Unpack, bitmap );
375 }
376 }
377 else if (ctx->RenderMode == GL_FEEDBACK) {
378 FLUSH_CURRENT(ctx, 0);
379 _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN );
380 _mesa_feedback_vertex( ctx,
381 ctx->Current.RasterPos,
382 ctx->Current.RasterColor,
383 ctx->Current.RasterTexCoords[0] );
384 }
385 else {
386 assert(ctx->RenderMode == GL_SELECT);
387 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */
388 }
389
390 /* update raster position */
391 ctx->Current.RasterPos[0] += xmove;
392 ctx->Current.RasterPos[1] += ymove;
393 ctx->PopAttribState |= GL_CURRENT_BIT;
394
395 if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
396 _mesa_flush(ctx);
397 }
398 }
399