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