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