Add surface storage allocation function to winsys interface.
[mesa.git] / src / mesa / pipe / i915simple / i915_surface.c
1 /**************************************************************************
2 *
3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * 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
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 #include "i915_context.h"
29 #include "i915_blit.h"
30 #include "i915_state.h"
31 #include "pipe/p_defines.h"
32 #include "pipe/p_inlines.h"
33 #include "pipe/p_util.h"
34 #include "pipe/p_inlines.h"
35 #include "pipe/p_winsys.h"
36
37
38 #define CLIP_TILE \
39 do { \
40 if (x >= ps->width) \
41 return; \
42 if (y >= ps->height) \
43 return; \
44 if (x + w > ps->width) \
45 w = ps->width - x; \
46 if (y + h > ps->height) \
47 h = ps->height -y; \
48 } while(0)
49
50
51 /**
52 * Note: this is exactly like a8r8g8b8_get_tile() in sp_surface.c
53 * Share it someday.
54 */
55 /** XXX this will go away eventually */
56 static void
57 i915_get_tile_rgba(struct pipe_context *pipe,
58 struct pipe_surface *ps,
59 uint x, uint y, uint w, uint h, float *p)
60 {
61 const unsigned *src
62 = ((const unsigned *) (ps->map))
63 + y * ps->pitch + x;
64 unsigned i, j;
65 unsigned w0 = w;
66
67 CLIP_TILE;
68
69 switch (ps->format) {
70 case PIPE_FORMAT_A8R8G8B8_UNORM:
71 for (i = 0; i < h; i++) {
72 float *pRow = p;
73 for (j = 0; j < w; j++) {
74 const unsigned pixel = src[j];
75 pRow[0] = UBYTE_TO_FLOAT((pixel >> 16) & 0xff);
76 pRow[1] = UBYTE_TO_FLOAT((pixel >> 8) & 0xff);
77 pRow[2] = UBYTE_TO_FLOAT((pixel >> 0) & 0xff);
78 pRow[3] = UBYTE_TO_FLOAT((pixel >> 24) & 0xff);
79 pRow += 4;
80 }
81 src += ps->pitch;
82 p += w0 * 4;
83 }
84 break;
85 case PIPE_FORMAT_S8Z24_UNORM:
86 {
87 const float scale = 1.0f / (float) 0xffffff;
88 for (i = 0; i < h; i++) {
89 float *pRow = p;
90 for (j = 0; j < w; j++) {
91 const unsigned pixel = src[j];
92 pRow[0] =
93 pRow[1] =
94 pRow[2] =
95 pRow[3] = (pixel & 0xffffff) * scale;
96 pRow += 4;
97 }
98 src += ps->pitch;
99 p += w0 * 4;
100 }
101 }
102 break;
103 default:
104 assert(0);
105 }
106 }
107
108
109 /** XXX this will go away eventually */
110 static void
111 i915_put_tile_rgba(struct pipe_context *pipe,
112 struct pipe_surface *ps,
113 uint x, uint y, uint w, uint h, const float *p)
114 {
115 unsigned *dst
116 = ((unsigned *) (ps->map))
117 + y * ps->pitch + x;
118 unsigned i, j;
119 unsigned w0 = w;
120
121 assert(ps->format == PIPE_FORMAT_A8R8G8B8_UNORM);
122
123 CLIP_TILE;
124
125 switch (ps->format) {
126 case PIPE_FORMAT_A8R8G8B8_UNORM:
127 for (i = 0; i < h; i++) {
128 const float *pRow = p;
129 for (j = 0; j < w; j++) {
130 unsigned r, g, b, a;
131 UNCLAMPED_FLOAT_TO_UBYTE(r, pRow[0]);
132 UNCLAMPED_FLOAT_TO_UBYTE(g, pRow[1]);
133 UNCLAMPED_FLOAT_TO_UBYTE(b, pRow[2]);
134 UNCLAMPED_FLOAT_TO_UBYTE(a, pRow[3]);
135 dst[j] = (a << 24) | (r << 16) | (g << 8) | b;
136 pRow += 4;
137 }
138 dst += ps->pitch;
139 p += w0 * 4;
140 }
141 break;
142 default:
143 assert(0);
144 }
145 }
146
147
148 /*
149 * XXX note: same as code in sp_surface.c
150 */
151 static void
152 i915_get_tile(struct pipe_context *pipe,
153 struct pipe_surface *ps,
154 uint x, uint y, uint w, uint h,
155 void *p, int dst_stride)
156 {
157 const uint cpp = ps->cpp;
158 const uint w0 = w;
159 const ubyte *pSrc;
160 ubyte *pDest;
161 uint i;
162
163 assert(ps->map);
164
165 CLIP_TILE;
166
167 if (dst_stride == 0) {
168 dst_stride = w0 * cpp;
169 }
170
171 pSrc = ps->map + (y * ps->pitch + x) * cpp;
172 pDest = (ubyte *) p;
173
174 for (i = 0; i < h; i++) {
175 memcpy(pDest, pSrc, w0 * cpp);
176 pDest += dst_stride;
177 pSrc += ps->pitch * cpp;
178 }
179 }
180
181
182 /*
183 * XXX note: same as code in sp_surface.c
184 */
185 static void
186 i915_put_tile(struct pipe_context *pipe,
187 struct pipe_surface *ps,
188 uint x, uint y, uint w, uint h,
189 const void *p, int src_stride)
190 {
191 const uint cpp = ps->cpp;
192 const uint w0 = w;
193 const ubyte *pSrc;
194 ubyte *pDest;
195 uint i;
196
197 assert(ps->map);
198
199 CLIP_TILE;
200
201 if (src_stride == 0) {
202 src_stride = w0 * cpp;
203 }
204
205 pSrc = (const ubyte *) p;
206 pDest = ps->map + (y * ps->pitch + x) * cpp;
207
208 for (i = 0; i < h; i++) {
209 memcpy(pDest, pSrc, w0 * cpp);
210 pDest += ps->pitch * cpp;
211 pSrc += src_stride;
212 }
213 }
214
215
216 /*
217 * XXX note: same as code in sp_surface.c
218 */
219 static struct pipe_surface *
220 i915_get_tex_surface(struct pipe_context *pipe,
221 struct pipe_texture *pt,
222 unsigned face, unsigned level, unsigned zslice)
223 {
224 struct i915_texture *tex = (struct i915_texture *)pt;
225 struct pipe_surface *ps;
226 unsigned offset; /* in bytes */
227
228 offset = tex->level_offset[level];
229
230 if (pt->target == PIPE_TEXTURE_CUBE) {
231 offset += tex->image_offset[level][face] * pt->cpp;
232 }
233 else if (pt->target == PIPE_TEXTURE_3D) {
234 offset += tex->image_offset[level][zslice] * pt->cpp;
235 }
236 else {
237 assert(face == 0);
238 assert(zslice == 0);
239 }
240
241 ps = pipe->winsys->surface_alloc(pipe->winsys);
242 if (ps) {
243 assert(ps->format);
244 assert(ps->refcount);
245 pipe->winsys->buffer_reference(pipe->winsys, &ps->buffer, tex->buffer);
246 ps->format = pt->format;
247 ps->cpp = pt->cpp;
248 ps->width = pt->width[level];
249 ps->height = pt->height[level];
250 ps->pitch = tex->pitch;
251 ps->offset = offset;
252 }
253 return ps;
254 }
255
256
257 /*
258 * XXX Move this into core Mesa?
259 */
260 static void
261 _mesa_copy_rect(ubyte * dst,
262 unsigned cpp,
263 unsigned dst_pitch,
264 unsigned dst_x,
265 unsigned dst_y,
266 unsigned width,
267 unsigned height,
268 const ubyte * src,
269 unsigned src_pitch,
270 unsigned src_x,
271 unsigned src_y)
272 {
273 unsigned i;
274
275 dst_pitch *= cpp;
276 src_pitch *= cpp;
277 dst += dst_x * cpp;
278 src += src_x * cpp;
279 dst += dst_y * dst_pitch;
280 src += src_y * dst_pitch;
281 width *= cpp;
282
283 if (width == dst_pitch && width == src_pitch)
284 memcpy(dst, src, height * width);
285 else {
286 for (i = 0; i < height; i++) {
287 memcpy(dst, src, width);
288 dst += dst_pitch;
289 src += src_pitch;
290 }
291 }
292 }
293
294
295 /* Upload data to a rectangular sub-region. Lots of choices how to do this:
296 *
297 * - memcpy by span to current destination
298 * - upload data as new buffer and blit
299 *
300 * Currently always memcpy.
301 */
302 static void
303 i915_surface_data(struct pipe_context *pipe,
304 struct pipe_surface *dst,
305 unsigned dstx, unsigned dsty,
306 const void *src, unsigned src_pitch,
307 unsigned srcx, unsigned srcy, unsigned width, unsigned height)
308 {
309 _mesa_copy_rect(pipe_surface_map(dst),
310 dst->cpp,
311 dst->pitch,
312 dstx, dsty, width, height, src, src_pitch, srcx, srcy);
313
314 pipe_surface_unmap(dst);
315 }
316
317
318 /* Assumes all values are within bounds -- no checking at this level -
319 * do it higher up if required.
320 */
321 static void
322 i915_surface_copy(struct pipe_context *pipe,
323 struct pipe_surface *dst,
324 unsigned dstx, unsigned dsty,
325 struct pipe_surface *src,
326 unsigned srcx, unsigned srcy, unsigned width, unsigned height)
327 {
328 assert( dst != src );
329 assert( dst->cpp == src->cpp );
330
331 if (0) {
332 _mesa_copy_rect(pipe_surface_map(dst),
333 dst->cpp,
334 dst->pitch,
335 dstx, dsty,
336 width, height,
337 pipe_surface_map(src),
338 src->pitch,
339 srcx, srcy);
340
341 pipe_surface_unmap(src);
342 pipe_surface_unmap(dst);
343 }
344 else {
345 i915_copy_blit( i915_context(pipe),
346 dst->cpp,
347 (short) src->pitch, src->buffer, src->offset,
348 (short) dst->pitch, dst->buffer, dst->offset,
349 (short) srcx, (short) srcy, (short) dstx, (short) dsty, (short) width, (short) height );
350 }
351 }
352
353 /* Fill a rectangular sub-region. Need better logic about when to
354 * push buffers into AGP - will currently do so whenever possible.
355 */
356 static ubyte *
357 get_pointer(struct pipe_surface *dst, unsigned x, unsigned y)
358 {
359 return dst->map + (y * dst->pitch + x) * dst->cpp;
360 }
361
362
363 static void
364 i915_surface_fill(struct pipe_context *pipe,
365 struct pipe_surface *dst,
366 unsigned dstx, unsigned dsty,
367 unsigned width, unsigned height, unsigned value)
368 {
369 if (0) {
370 unsigned i, j;
371
372 (void)pipe_surface_map(dst);
373
374 switch (dst->cpp) {
375 case 1: {
376 ubyte *row = get_pointer(dst, dstx, dsty);
377 for (i = 0; i < height; i++) {
378 memset(row, value, width);
379 row += dst->pitch;
380 }
381 }
382 break;
383 case 2: {
384 ushort *row = (ushort *) get_pointer(dst, dstx, dsty);
385 for (i = 0; i < height; i++) {
386 for (j = 0; j < width; j++)
387 row[j] = (ushort) value;
388 row += dst->pitch;
389 }
390 }
391 break;
392 case 4: {
393 unsigned *row = (unsigned *) get_pointer(dst, dstx, dsty);
394 for (i = 0; i < height; i++) {
395 for (j = 0; j < width; j++)
396 row[j] = value;
397 row += dst->pitch;
398 }
399 }
400 break;
401 default:
402 assert(0);
403 break;
404 }
405 }
406 else {
407 i915_fill_blit( i915_context(pipe),
408 dst->cpp,
409 (short) dst->pitch,
410 dst->buffer, dst->offset,
411 (short) dstx, (short) dsty,
412 (short) width, (short) height,
413 value );
414 }
415 }
416
417
418 void
419 i915_init_surface_functions(struct i915_context *i915)
420 {
421 i915->pipe.get_tex_surface = i915_get_tex_surface;
422 i915->pipe.get_tile = i915_get_tile;
423 i915->pipe.put_tile = i915_put_tile;
424 i915->pipe.get_tile_rgba = i915_get_tile_rgba;
425 i915->pipe.put_tile_rgba = i915_put_tile_rgba;
426 i915->pipe.surface_data = i915_surface_data;
427 i915->pipe.surface_copy = i915_surface_copy;
428 i915->pipe.surface_fill = i915_surface_fill;
429 }