Merge remote-tracking branch 'jekstrand/wip/i965-uniforms' into vulkan
[mesa.git] / src / mesa / swrast / s_zoom.c
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 "main/glheader.h"
26 #include "main/macros.h"
27 #include "main/imports.h"
28 #include "main/format_pack.h"
29
30 #include "s_context.h"
31 #include "s_span.h"
32 #include "s_stencil.h"
33 #include "s_zoom.h"
34
35
36 /**
37 * Compute the bounds of the region resulting from zooming a pixel span.
38 * The resulting region will be entirely inside the window/scissor bounds
39 * so no additional clipping is needed.
40 * \param imageX, imageY position of the mage being drawn (gl WindowPos)
41 * \param spanX, spanY position of span being drawing
42 * \param width number of pixels in span
43 * \param x0, x1 returned X bounds of zoomed region [x0, x1)
44 * \param y0, y1 returned Y bounds of zoomed region [y0, y1)
45 * \return GL_TRUE if any zoomed pixels visible, GL_FALSE if totally clipped
46 */
47 static GLboolean
48 compute_zoomed_bounds(struct gl_context *ctx, GLint imageX, GLint imageY,
49 GLint spanX, GLint spanY, GLint width,
50 GLint *x0, GLint *x1, GLint *y0, GLint *y1)
51 {
52 const struct gl_framebuffer *fb = ctx->DrawBuffer;
53 GLint c0, c1, r0, r1;
54
55 assert(spanX >= imageX);
56 assert(spanY >= imageY);
57
58 /*
59 * Compute destination columns: [c0, c1)
60 */
61 c0 = imageX + (GLint) ((spanX - imageX) * ctx->Pixel.ZoomX);
62 c1 = imageX + (GLint) ((spanX + width - imageX) * ctx->Pixel.ZoomX);
63 if (c1 < c0) {
64 /* swap */
65 GLint tmp = c1;
66 c1 = c0;
67 c0 = tmp;
68 }
69 c0 = CLAMP(c0, fb->_Xmin, fb->_Xmax);
70 c1 = CLAMP(c1, fb->_Xmin, fb->_Xmax);
71 if (c0 == c1) {
72 return GL_FALSE; /* no width */
73 }
74
75 /*
76 * Compute destination rows: [r0, r1)
77 */
78 r0 = imageY + (GLint) ((spanY - imageY) * ctx->Pixel.ZoomY);
79 r1 = imageY + (GLint) ((spanY + 1 - imageY) * ctx->Pixel.ZoomY);
80 if (r1 < r0) {
81 /* swap */
82 GLint tmp = r1;
83 r1 = r0;
84 r0 = tmp;
85 }
86 r0 = CLAMP(r0, fb->_Ymin, fb->_Ymax);
87 r1 = CLAMP(r1, fb->_Ymin, fb->_Ymax);
88 if (r0 == r1) {
89 return GL_FALSE; /* no height */
90 }
91
92 *x0 = c0;
93 *x1 = c1;
94 *y0 = r0;
95 *y1 = r1;
96
97 return GL_TRUE;
98 }
99
100
101 /**
102 * Convert a zoomed x image coordinate back to an unzoomed x coord.
103 * 'zx' is screen position of a pixel in the zoomed image, who's left edge
104 * is at 'imageX'.
105 * return corresponding x coord in the original, unzoomed image.
106 * This can use this for unzooming X or Y values.
107 */
108 static inline GLint
109 unzoom_x(GLfloat zoomX, GLint imageX, GLint zx)
110 {
111 /*
112 zx = imageX + (x - imageX) * zoomX;
113 zx - imageX = (x - imageX) * zoomX;
114 (zx - imageX) / zoomX = x - imageX;
115 */
116 GLint x;
117 if (zoomX < 0.0F)
118 zx++;
119 x = imageX + (GLint) ((zx - imageX) / zoomX);
120 return x;
121 }
122
123
124
125 /**
126 * Helper function called from _swrast_write_zoomed_rgba/rgb/
127 * index/depth_span().
128 */
129 static void
130 zoom_span( struct gl_context *ctx, GLint imgX, GLint imgY, const SWspan *span,
131 const GLvoid *src, GLenum format )
132 {
133 SWcontext *swrast = SWRAST_CONTEXT(ctx);
134 SWspan zoomed;
135 GLint x0, x1, y0, y1;
136 GLint zoomedWidth;
137
138 if (!compute_zoomed_bounds(ctx, imgX, imgY, span->x, span->y, span->end,
139 &x0, &x1, &y0, &y1)) {
140 return; /* totally clipped */
141 }
142
143 if (!swrast->ZoomedArrays) {
144 /* allocate on demand */
145 swrast->ZoomedArrays = (SWspanarrays *) calloc(1, sizeof(SWspanarrays));
146 if (!swrast->ZoomedArrays)
147 return;
148 }
149
150 zoomedWidth = x1 - x0;
151 assert(zoomedWidth > 0);
152 assert(zoomedWidth <= SWRAST_MAX_WIDTH);
153
154 /* no pixel arrays! must be horizontal spans. */
155 assert((span->arrayMask & SPAN_XY) == 0);
156 assert(span->primitive == GL_BITMAP);
157
158 INIT_SPAN(zoomed, GL_BITMAP);
159 zoomed.x = x0;
160 zoomed.end = zoomedWidth;
161 zoomed.array = swrast->ZoomedArrays;
162 zoomed.array->ChanType = span->array->ChanType;
163 if (zoomed.array->ChanType == GL_UNSIGNED_BYTE)
164 zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->rgba8;
165 else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT)
166 zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->rgba16;
167 else
168 zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->attribs[VARYING_SLOT_COL0];
169
170 COPY_4V(zoomed.attrStart[VARYING_SLOT_POS], span->attrStart[VARYING_SLOT_POS]);
171 COPY_4V(zoomed.attrStepX[VARYING_SLOT_POS], span->attrStepX[VARYING_SLOT_POS]);
172 COPY_4V(zoomed.attrStepY[VARYING_SLOT_POS], span->attrStepY[VARYING_SLOT_POS]);
173
174 zoomed.attrStart[VARYING_SLOT_FOGC][0] = span->attrStart[VARYING_SLOT_FOGC][0];
175 zoomed.attrStepX[VARYING_SLOT_FOGC][0] = span->attrStepX[VARYING_SLOT_FOGC][0];
176 zoomed.attrStepY[VARYING_SLOT_FOGC][0] = span->attrStepY[VARYING_SLOT_FOGC][0];
177
178 if (format == GL_RGBA || format == GL_RGB) {
179 /* copy Z info */
180 zoomed.z = span->z;
181 zoomed.zStep = span->zStep;
182 /* we'll generate an array of colorss */
183 zoomed.interpMask = span->interpMask & ~SPAN_RGBA;
184 zoomed.arrayMask |= SPAN_RGBA;
185 zoomed.arrayAttribs |= VARYING_BIT_COL0; /* we'll produce these values */
186 assert(span->arrayMask & SPAN_RGBA);
187 }
188 else if (format == GL_DEPTH_COMPONENT) {
189 /* Copy color info */
190 zoomed.red = span->red;
191 zoomed.green = span->green;
192 zoomed.blue = span->blue;
193 zoomed.alpha = span->alpha;
194 zoomed.redStep = span->redStep;
195 zoomed.greenStep = span->greenStep;
196 zoomed.blueStep = span->blueStep;
197 zoomed.alphaStep = span->alphaStep;
198 /* we'll generate an array of depth values */
199 zoomed.interpMask = span->interpMask & ~SPAN_Z;
200 zoomed.arrayMask |= SPAN_Z;
201 assert(span->arrayMask & SPAN_Z);
202 }
203 else {
204 _mesa_problem(ctx, "Bad format in zoom_span");
205 return;
206 }
207
208 /* zoom the span horizontally */
209 if (format == GL_RGBA) {
210 if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) {
211 const GLubyte (*rgba)[4] = (const GLubyte (*)[4]) src;
212 GLint i;
213 for (i = 0; i < zoomedWidth; i++) {
214 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
215 assert(j >= 0);
216 assert(j < (GLint) span->end);
217 COPY_4UBV(zoomed.array->rgba8[i], rgba[j]);
218 }
219 }
220 else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
221 const GLushort (*rgba)[4] = (const GLushort (*)[4]) src;
222 GLint i;
223 for (i = 0; i < zoomedWidth; i++) {
224 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
225 assert(j >= 0);
226 assert(j < (GLint) span->end);
227 COPY_4V(zoomed.array->rgba16[i], rgba[j]);
228 }
229 }
230 else {
231 const GLfloat (*rgba)[4] = (const GLfloat (*)[4]) src;
232 GLint i;
233 for (i = 0; i < zoomedWidth; i++) {
234 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
235 assert(j >= 0);
236 assert(j < (GLint) span->end);
237 COPY_4V(zoomed.array->attribs[VARYING_SLOT_COL0][i], rgba[j]);
238 }
239 }
240 }
241 else if (format == GL_RGB) {
242 if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) {
243 const GLubyte (*rgb)[3] = (const GLubyte (*)[3]) src;
244 GLint i;
245 for (i = 0; i < zoomedWidth; i++) {
246 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
247 assert(j >= 0);
248 assert(j < (GLint) span->end);
249 zoomed.array->rgba8[i][0] = rgb[j][0];
250 zoomed.array->rgba8[i][1] = rgb[j][1];
251 zoomed.array->rgba8[i][2] = rgb[j][2];
252 zoomed.array->rgba8[i][3] = 0xff;
253 }
254 }
255 else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
256 const GLushort (*rgb)[3] = (const GLushort (*)[3]) src;
257 GLint i;
258 for (i = 0; i < zoomedWidth; i++) {
259 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
260 assert(j >= 0);
261 assert(j < (GLint) span->end);
262 zoomed.array->rgba16[i][0] = rgb[j][0];
263 zoomed.array->rgba16[i][1] = rgb[j][1];
264 zoomed.array->rgba16[i][2] = rgb[j][2];
265 zoomed.array->rgba16[i][3] = 0xffff;
266 }
267 }
268 else {
269 const GLfloat (*rgb)[3] = (const GLfloat (*)[3]) src;
270 GLint i;
271 for (i = 0; i < zoomedWidth; i++) {
272 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
273 assert(j >= 0);
274 assert(j < (GLint) span->end);
275 zoomed.array->attribs[VARYING_SLOT_COL0][i][0] = rgb[j][0];
276 zoomed.array->attribs[VARYING_SLOT_COL0][i][1] = rgb[j][1];
277 zoomed.array->attribs[VARYING_SLOT_COL0][i][2] = rgb[j][2];
278 zoomed.array->attribs[VARYING_SLOT_COL0][i][3] = 1.0F;
279 }
280 }
281 }
282 else if (format == GL_DEPTH_COMPONENT) {
283 const GLuint *zValues = (const GLuint *) src;
284 GLint i;
285 for (i = 0; i < zoomedWidth; i++) {
286 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
287 assert(j >= 0);
288 assert(j < (GLint) span->end);
289 zoomed.array->z[i] = zValues[j];
290 }
291 /* Now, fall into the RGB path below */
292 format = GL_RGBA;
293 }
294
295 /* write the span in rows [r0, r1) */
296 if (format == GL_RGBA || format == GL_RGB) {
297 /* Writing the span may modify the colors, so make a backup now if we're
298 * going to call _swrast_write_zoomed_span() more than once.
299 * Also, clipping may change the span end value, so store it as well.
300 */
301 const GLint end = zoomed.end; /* save */
302 void *rgbaSave;
303 const GLint pixelSize =
304 (zoomed.array->ChanType == GL_UNSIGNED_BYTE) ? 4 * sizeof(GLubyte) :
305 ((zoomed.array->ChanType == GL_UNSIGNED_SHORT) ? 4 * sizeof(GLushort)
306 : 4 * sizeof(GLfloat));
307
308 rgbaSave = malloc(zoomed.end * pixelSize);
309 if (!rgbaSave) {
310 return;
311 }
312
313 if (y1 - y0 > 1) {
314 memcpy(rgbaSave, zoomed.array->rgba, zoomed.end * pixelSize);
315 }
316 for (zoomed.y = y0; zoomed.y < y1; zoomed.y++) {
317 _swrast_write_rgba_span(ctx, &zoomed);
318 zoomed.end = end; /* restore */
319 if (y1 - y0 > 1) {
320 /* restore the colors */
321 memcpy(zoomed.array->rgba, rgbaSave, zoomed.end * pixelSize);
322 }
323 }
324
325 free(rgbaSave);
326 }
327 }
328
329
330 void
331 _swrast_write_zoomed_rgba_span(struct gl_context *ctx, GLint imgX, GLint imgY,
332 const SWspan *span, const GLvoid *rgba)
333 {
334 zoom_span(ctx, imgX, imgY, span, rgba, GL_RGBA);
335 }
336
337
338 void
339 _swrast_write_zoomed_rgb_span(struct gl_context *ctx, GLint imgX, GLint imgY,
340 const SWspan *span, const GLvoid *rgb)
341 {
342 zoom_span(ctx, imgX, imgY, span, rgb, GL_RGB);
343 }
344
345
346 void
347 _swrast_write_zoomed_depth_span(struct gl_context *ctx, GLint imgX, GLint imgY,
348 const SWspan *span)
349 {
350 zoom_span(ctx, imgX, imgY, span,
351 (const GLvoid *) span->array->z, GL_DEPTH_COMPONENT);
352 }
353
354
355 /**
356 * Zoom/write stencil values.
357 * No per-fragment operations are applied.
358 */
359 void
360 _swrast_write_zoomed_stencil_span(struct gl_context *ctx, GLint imgX, GLint imgY,
361 GLint width, GLint spanX, GLint spanY,
362 const GLubyte stencil[])
363 {
364 GLubyte *zoomedVals;
365 GLint x0, x1, y0, y1, y;
366 GLint i, zoomedWidth;
367
368 if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
369 &x0, &x1, &y0, &y1)) {
370 return; /* totally clipped */
371 }
372
373 zoomedWidth = x1 - x0;
374 assert(zoomedWidth > 0);
375 assert(zoomedWidth <= SWRAST_MAX_WIDTH);
376
377 zoomedVals = malloc(zoomedWidth * sizeof(GLubyte));
378 if (!zoomedVals)
379 return;
380
381 /* zoom the span horizontally */
382 for (i = 0; i < zoomedWidth; i++) {
383 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
384 assert(j >= 0);
385 assert(j < width);
386 zoomedVals[i] = stencil[j];
387 }
388
389 /* write the zoomed spans */
390 for (y = y0; y < y1; y++) {
391 _swrast_write_stencil_span(ctx, zoomedWidth, x0, y, zoomedVals);
392 }
393
394 free(zoomedVals);
395 }
396
397
398 /**
399 * Zoom/write 32-bit Z values.
400 * No per-fragment operations are applied.
401 */
402 void
403 _swrast_write_zoomed_z_span(struct gl_context *ctx, GLint imgX, GLint imgY,
404 GLint width, GLint spanX, GLint spanY,
405 const GLuint *zVals)
406 {
407 struct gl_renderbuffer *rb =
408 ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
409 GLuint *zoomedVals;
410 GLint x0, x1, y0, y1, y;
411 GLint i, zoomedWidth;
412
413 if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
414 &x0, &x1, &y0, &y1)) {
415 return; /* totally clipped */
416 }
417
418 zoomedWidth = x1 - x0;
419 assert(zoomedWidth > 0);
420 assert(zoomedWidth <= SWRAST_MAX_WIDTH);
421
422 zoomedVals = malloc(zoomedWidth * sizeof(GLuint));
423 if (!zoomedVals)
424 return;
425
426 /* zoom the span horizontally */
427 for (i = 0; i < zoomedWidth; i++) {
428 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
429 assert(j >= 0);
430 assert(j < width);
431 zoomedVals[i] = zVals[j];
432 }
433
434 /* write the zoomed spans */
435 for (y = y0; y < y1; y++) {
436 GLubyte *dst = _swrast_pixel_address(rb, x0, y);
437 _mesa_pack_uint_z_row(rb->Format, zoomedWidth, zoomedVals, dst);
438 }
439
440 free(zoomedVals);
441 }