OSDN Git Service

Merge branch 'pipe-video' of git://anongit.freedesktop.org/~deathsimple/xvmc-r600...
[android-x86/external-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 "enums.h"
31 #include "feedback.h"
32 #include "framebuffer.h"
33 #include "image.h"
34 #include "readpix.h"
35 #include "shaderobj.h"
36 #include "state.h"
37 #include "dispatch.h"
38
39
40 #if FEATURE_drawpix
41
42
43 /**
44  * If a fragment program is enabled, check that it's valid.
45  * \return GL_TRUE if valid, GL_FALSE otherwise
46  */
47 static GLboolean
48 valid_fragment_program(struct gl_context *ctx)
49 {
50    return !(ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled);
51 }
52
53
54 /*
55  * Execute glDrawPixels
56  */
57 static void GLAPIENTRY
58 _mesa_DrawPixels( GLsizei width, GLsizei height,
59                   GLenum format, GLenum type, const GLvoid *pixels )
60 {
61    GET_CURRENT_CONTEXT(ctx);
62    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
63
64    if (width < 0 || height < 0) {
65       _mesa_error( ctx, GL_INVALID_VALUE, "glDrawPixels(width or height < 0" );
66       return;
67    }
68
69    /* We're not using the current vertex program, and the driver may install
70     * it's own.
71     */
72    _mesa_set_vp_override(ctx, GL_TRUE);
73
74    if (ctx->NewState) {
75       _mesa_update_state(ctx);
76    }
77
78    if (!valid_fragment_program(ctx)) {
79       _mesa_error(ctx, GL_INVALID_OPERATION,
80                   "glDrawPixels (invalid fragment program)");
81       goto end;
82    }
83
84    if (_mesa_error_check_format_type(ctx, format, type, GL_TRUE)) {
85       /* the error was already recorded */
86       goto end;
87    }
88
89    if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
90       _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
91                   "glDrawPixels(incomplete framebuffer)" );
92       goto end;
93    }
94
95    if (!ctx->Current.RasterPosValid) {
96       goto end; /* no-op, not an error */
97    }
98
99    if (_mesa_is_integer_format(format) &&
100        !_mesa_is_fragment_shader_active(ctx)) {
101       /* A fragment shader is required when drawing integer formats */
102       _mesa_error(ctx, GL_INVALID_OPERATION,
103                   "glDrawPixels(integer format but no fragment shader)");
104       goto end;
105    }
106
107    if (ctx->RenderMode == GL_RENDER) {
108       if (width > 0 && height > 0) {
109          /* Round, to satisfy conformance tests (matches SGI's OpenGL) */
110          GLint x = IROUND(ctx->Current.RasterPos[0]);
111          GLint y = IROUND(ctx->Current.RasterPos[1]);
112
113          if (ctx->Unpack.BufferObj->Name) {
114             /* unpack from PBO */
115             if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 1,
116                                            format, type, pixels)) {
117                _mesa_error(ctx, GL_INVALID_OPERATION,
118                            "glDrawPixels(invalid PBO access)");
119                goto end;
120             }
121             if (_mesa_bufferobj_mapped(ctx->Unpack.BufferObj)) {
122                /* buffer is mapped - that's an error */
123                _mesa_error(ctx, GL_INVALID_OPERATION,
124                            "glDrawPixels(PBO is mapped)");
125                goto end;
126             }
127          }
128
129          ctx->Driver.DrawPixels(ctx, x, y, width, height, format, type,
130                                 &ctx->Unpack, pixels);
131       }
132    }
133    else if (ctx->RenderMode == GL_FEEDBACK) {
134       /* Feedback the current raster pos info */
135       FLUSH_CURRENT( ctx, 0 );
136       _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN );
137       _mesa_feedback_vertex( ctx,
138                              ctx->Current.RasterPos,
139                              ctx->Current.RasterColor,
140                              ctx->Current.RasterTexCoords[0] );
141    }
142    else {
143       ASSERT(ctx->RenderMode == GL_SELECT);
144       /* Do nothing.  See OpenGL Spec, Appendix B, Corollary 6. */
145    }
146
147 end:
148    _mesa_set_vp_override(ctx, GL_FALSE);
149 }
150
151
152 static void GLAPIENTRY
153 _mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height,
154                   GLenum type )
155 {
156    GET_CURRENT_CONTEXT(ctx);
157    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
158
159    if (width < 0 || height < 0) {
160       _mesa_error(ctx, GL_INVALID_VALUE, "glCopyPixels(width or height < 0)");
161       return;
162    }
163
164    /* Note: more detailed 'type' checking is done by the
165     * _mesa_source/dest_buffer_exists() calls below.  That's where we
166     * check if the stencil buffer exists, etc.
167     */
168    if (type != GL_COLOR &&
169        type != GL_DEPTH &&
170        type != GL_STENCIL &&
171        type != GL_DEPTH_STENCIL) {
172       _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels(type=%s)",
173                   _mesa_lookup_enum_by_nr(type));
174       return;
175    }
176
177    /* We're not using the current vertex program, and the driver may install
178     * it's own.
179     */
180    _mesa_set_vp_override(ctx, GL_TRUE);
181
182    if (ctx->NewState) {
183       _mesa_update_state(ctx);
184    }
185
186    if (!valid_fragment_program(ctx)) {
187       _mesa_error(ctx, GL_INVALID_OPERATION,
188                   "glCopyPixels (invalid fragment program)");
189       goto end;
190    }
191
192    if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
193        ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
194       _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
195                   "glCopyPixels(incomplete framebuffer)" );
196       goto end;
197    }
198
199    if (!_mesa_source_buffer_exists(ctx, type) ||
200        !_mesa_dest_buffer_exists(ctx, type)) {
201       _mesa_error(ctx, GL_INVALID_OPERATION,
202                   "glCopyPixels(missing source or dest buffer)");
203       goto end;
204    }
205
206    if (!ctx->Current.RasterPosValid || width ==0 || height == 0) {
207       goto end; /* no-op, not an error */
208    }
209
210    if (ctx->RenderMode == GL_RENDER) {
211       /* Round to satisfy conformance tests (matches SGI's OpenGL) */
212       if (width > 0 && height > 0) {
213          GLint destx = IROUND(ctx->Current.RasterPos[0]);
214          GLint desty = IROUND(ctx->Current.RasterPos[1]);
215          ctx->Driver.CopyPixels( ctx, srcx, srcy, width, height, destx, desty,
216                                  type );
217       }
218    }
219    else if (ctx->RenderMode == GL_FEEDBACK) {
220       FLUSH_CURRENT( ctx, 0 );
221       _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_COPY_PIXEL_TOKEN );
222       _mesa_feedback_vertex( ctx, 
223                              ctx->Current.RasterPos,
224                              ctx->Current.RasterColor,
225                              ctx->Current.RasterTexCoords[0] );
226    }
227    else {
228       ASSERT(ctx->RenderMode == GL_SELECT);
229       /* Do nothing.  See OpenGL Spec, Appendix B, Corollary 6. */
230    }
231
232 end:
233    _mesa_set_vp_override(ctx, GL_FALSE);
234 }
235
236
237 static void GLAPIENTRY
238 _mesa_Bitmap( GLsizei width, GLsizei height,
239               GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove,
240               const GLubyte *bitmap )
241 {
242    GET_CURRENT_CONTEXT(ctx);
243    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
244
245    if (width < 0 || height < 0) {
246       _mesa_error( ctx, GL_INVALID_VALUE, "glBitmap(width or height < 0)" );
247       return;
248    }
249
250    if (!ctx->Current.RasterPosValid) {
251       return;    /* do nothing */
252    }
253
254    if (ctx->NewState) {
255       _mesa_update_state(ctx);
256    }
257
258    if (!valid_fragment_program(ctx)) {
259       _mesa_error(ctx, GL_INVALID_OPERATION,
260                   "glBitmap (invalid fragment program)");
261       return;
262    }
263
264    if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
265       _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
266                   "glBitmap(incomplete framebuffer)");
267       return;
268    }
269
270    if (ctx->RenderMode == GL_RENDER) {
271       /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */
272       if (width > 0 && height > 0) {
273          const GLfloat epsilon = 0.0001F;
274          GLint x = IFLOOR(ctx->Current.RasterPos[0] + epsilon - xorig);
275          GLint y = IFLOOR(ctx->Current.RasterPos[1] + epsilon - yorig);
276
277          if (ctx->Unpack.BufferObj->Name) {
278             /* unpack from PBO */
279             if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 1,
280                                            GL_COLOR_INDEX, GL_BITMAP,
281                                            (GLvoid *) bitmap)) {
282                _mesa_error(ctx, GL_INVALID_OPERATION,
283                            "glBitmap(invalid PBO access)");
284                return;
285             }
286             if (_mesa_bufferobj_mapped(ctx->Unpack.BufferObj)) {
287                /* buffer is mapped - that's an error */
288                _mesa_error(ctx, GL_INVALID_OPERATION,
289                            "glBitmap(PBO is mapped)");
290                return;
291             }
292          }
293
294          ctx->Driver.Bitmap( ctx, x, y, width, height, &ctx->Unpack, bitmap );
295       }
296    }
297 #if _HAVE_FULL_GL
298    else if (ctx->RenderMode == GL_FEEDBACK) {
299       FLUSH_CURRENT(ctx, 0);
300       _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN );
301       _mesa_feedback_vertex( ctx,
302                              ctx->Current.RasterPos,
303                              ctx->Current.RasterColor,
304                              ctx->Current.RasterTexCoords[0] );
305    }
306    else {
307       ASSERT(ctx->RenderMode == GL_SELECT);
308       /* Do nothing.  See OpenGL Spec, Appendix B, Corollary 6. */
309    }
310 #endif
311
312    /* update raster position */
313    ctx->Current.RasterPos[0] += xmove;
314    ctx->Current.RasterPos[1] += ymove;
315 }
316
317
318 void
319 _mesa_init_drawpix_dispatch(struct _glapi_table *disp)
320 {
321    SET_Bitmap(disp, _mesa_Bitmap);
322    SET_CopyPixels(disp, _mesa_CopyPixels);
323    SET_DrawPixels(disp, _mesa_DrawPixels);
324 }
325
326
327 #endif /* FEATURE_drawpix */