Merge branch 'pipe-video' of git://anongit.freedesktop.org/~deathsimple/xvmc-r600...
[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 */