1 /**************************************************************************
2  *
3  * Copyright 2009 VMware, Inc.  All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sub license, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial portions
15  * 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
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  **************************************************************************/
26 
27 /**
28  * @file
29  * Surface utility functions.
30  *
31  * @author Brian Paul
32  */
33 
34 
35 #include "pipe/p_defines.h"
36 #include "pipe/p_screen.h"
37 #include "pipe/p_state.h"
38 
39 #include "util/u_format.h"
40 #include "util/u_inlines.h"
41 #include "util/u_rect.h"
42 #include "util/u_surface.h"
43 #include "util/u_pack_color.h"
44 
45 
46 /**
47  * Initialize a pipe_surface object.  'view' is considered to have
48  * uninitialized contents.
49  */
50 void
u_surface_default_template(struct pipe_surface * surf,const struct pipe_resource * texture,unsigned bind)51 u_surface_default_template(struct pipe_surface *surf,
52                            const struct pipe_resource *texture,
53                            unsigned bind)
54 {
55    memset(surf, 0, sizeof(*surf));
56 
57    surf->format = texture->format;
58    /* XXX should filter out all non-rt/ds bind flags ? */
59    surf->usage = bind;
60 }
61 
62 /**
63  * Helper to quickly create an RGBA rendering surface of a certain size.
64  * \param textureOut  returns the new texture
65  * \param surfaceOut  returns the new surface
66  * \return TRUE for success, FALSE if failure
67  */
68 boolean
util_create_rgba_surface(struct pipe_context * pipe,uint width,uint height,uint bind,struct pipe_resource ** textureOut,struct pipe_surface ** surfaceOut)69 util_create_rgba_surface(struct pipe_context *pipe,
70                          uint width, uint height,
71                          uint bind,
72                          struct pipe_resource **textureOut,
73                          struct pipe_surface **surfaceOut)
74 {
75    static const enum pipe_format rgbaFormats[] = {
76       PIPE_FORMAT_B8G8R8A8_UNORM,
77       PIPE_FORMAT_A8R8G8B8_UNORM,
78       PIPE_FORMAT_A8B8G8R8_UNORM,
79       PIPE_FORMAT_NONE
80    };
81    const uint target = PIPE_TEXTURE_2D;
82    enum pipe_format format = PIPE_FORMAT_NONE;
83    struct pipe_resource templ;
84    struct pipe_surface surf_templ;
85    struct pipe_screen *screen = pipe->screen;
86    uint i;
87 
88    /* Choose surface format */
89    for (i = 0; rgbaFormats[i]; i++) {
90       if (screen->is_format_supported(screen, rgbaFormats[i],
91                                       target, 0, bind)) {
92          format = rgbaFormats[i];
93          break;
94       }
95    }
96    if (format == PIPE_FORMAT_NONE)
97       return FALSE;  /* unable to get an rgba format!?! */
98 
99    /* create texture */
100    memset(&templ, 0, sizeof(templ));
101    templ.target = target;
102    templ.format = format;
103    templ.last_level = 0;
104    templ.width0 = width;
105    templ.height0 = height;
106    templ.depth0 = 1;
107    templ.array_size = 1;
108    templ.bind = bind;
109 
110    *textureOut = screen->resource_create(screen, &templ);
111    if (!*textureOut)
112       return FALSE;
113 
114    /* create surface */
115    u_surface_default_template(&surf_templ, *textureOut, bind);
116    /* create surface / view into texture */
117    *surfaceOut = pipe->create_surface(pipe,
118                                       *textureOut,
119                                       &surf_templ);
120    if (!*surfaceOut) {
121       pipe_resource_reference(textureOut, NULL);
122       return FALSE;
123    }
124 
125    return TRUE;
126 }
127 
128 
129 /**
130  * Release the surface and texture from util_create_rgba_surface().
131  */
132 void
util_destroy_rgba_surface(struct pipe_resource * texture,struct pipe_surface * surface)133 util_destroy_rgba_surface(struct pipe_resource *texture,
134                           struct pipe_surface *surface)
135 {
136    pipe_surface_reference(&surface, NULL);
137    pipe_resource_reference(&texture, NULL);
138 }
139 
140 
141 
142 /**
143  * Fallback function for pipe->resource_copy_region().
144  * Note: (X,Y)=(0,0) is always the upper-left corner.
145  */
146 void
util_resource_copy_region(struct pipe_context * pipe,struct pipe_resource * dst,unsigned dst_level,unsigned dst_x,unsigned dst_y,unsigned dst_z,struct pipe_resource * src,unsigned src_level,const struct pipe_box * src_box)147 util_resource_copy_region(struct pipe_context *pipe,
148                           struct pipe_resource *dst,
149                           unsigned dst_level,
150                           unsigned dst_x, unsigned dst_y, unsigned dst_z,
151                           struct pipe_resource *src,
152                           unsigned src_level,
153                           const struct pipe_box *src_box)
154 {
155    struct pipe_transfer *src_trans, *dst_trans;
156    void *dst_map;
157    const void *src_map;
158    enum pipe_format src_format, dst_format;
159    unsigned w = src_box->width;
160    unsigned h = src_box->height;
161 
162    assert(src && dst);
163    if (!src || !dst)
164       return;
165 
166    assert((src->target == PIPE_BUFFER && dst->target == PIPE_BUFFER) ||
167           (src->target != PIPE_BUFFER && dst->target != PIPE_BUFFER));
168 
169    src_format = src->format;
170    dst_format = dst->format;
171 
172    src_trans = pipe_get_transfer(pipe,
173                                  src,
174                                  src_level,
175                                  src_box->z,
176                                  PIPE_TRANSFER_READ,
177                                  src_box->x, src_box->y, w, h);
178 
179    dst_trans = pipe_get_transfer(pipe,
180                                  dst,
181                                  dst_level,
182                                  dst_z,
183                                  PIPE_TRANSFER_WRITE,
184                                  dst_x, dst_y, w, h);
185 
186    assert(util_format_get_blocksize(dst_format) == util_format_get_blocksize(src_format));
187    assert(util_format_get_blockwidth(dst_format) == util_format_get_blockwidth(src_format));
188    assert(util_format_get_blockheight(dst_format) == util_format_get_blockheight(src_format));
189 
190    src_map = pipe->transfer_map(pipe, src_trans);
191    dst_map = pipe->transfer_map(pipe, dst_trans);
192 
193    assert(src_map);
194    assert(dst_map);
195 
196    if (src_map && dst_map) {
197       if (dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER) {
198          memcpy(dst_map, src_map, w);
199       } else {
200          util_copy_rect(dst_map,
201                         dst_format,
202                         dst_trans->stride,
203                         0, 0,
204                         w, h,
205                         src_map,
206                         src_trans->stride,
207                         0,
208                         0);
209       }
210    }
211 
212    pipe->transfer_unmap(pipe, src_trans);
213    pipe->transfer_unmap(pipe, dst_trans);
214 
215    pipe->transfer_destroy(pipe, src_trans);
216    pipe->transfer_destroy(pipe, dst_trans);
217 }
218 
219 
220 
221 #define UBYTE_TO_USHORT(B) ((B) | ((B) << 8))
222 
223 
224 /**
225  * Fallback for pipe->clear_render_target() function.
226  * XXX this looks too hackish to be really useful.
227  * cpp > 4 looks like a gross hack at best...
228  * Plus can't use these transfer fallbacks when clearing
229  * multisampled surfaces for instance.
230  */
231 void
util_clear_render_target(struct pipe_context * pipe,struct pipe_surface * dst,const union pipe_color_union * color,unsigned dstx,unsigned dsty,unsigned width,unsigned height)232 util_clear_render_target(struct pipe_context *pipe,
233                          struct pipe_surface *dst,
234                          const union pipe_color_union *color,
235                          unsigned dstx, unsigned dsty,
236                          unsigned width, unsigned height)
237 {
238    struct pipe_transfer *dst_trans;
239    void *dst_map;
240    union util_color uc;
241 
242    assert(dst->texture);
243    if (!dst->texture)
244       return;
245    /* XXX: should handle multiple layers */
246    dst_trans = pipe_get_transfer(pipe,
247                                  dst->texture,
248                                  dst->u.tex.level,
249                                  dst->u.tex.first_layer,
250                                  PIPE_TRANSFER_WRITE,
251                                  dstx, dsty, width, height);
252 
253    dst_map = pipe->transfer_map(pipe, dst_trans);
254 
255    assert(dst_map);
256 
257    if (dst_map) {
258       assert(dst_trans->stride > 0);
259 
260       util_pack_color(color->f, dst->texture->format, &uc);
261       util_fill_rect(dst_map, dst->texture->format,
262                      dst_trans->stride,
263                      0, 0, width, height, &uc);
264    }
265 
266    pipe->transfer_unmap(pipe, dst_trans);
267    pipe->transfer_destroy(pipe, dst_trans);
268 }
269 
270 /**
271  * Fallback for pipe->clear_stencil() function.
272  * sw fallback doesn't look terribly useful here.
273  * Plus can't use these transfer fallbacks when clearing
274  * multisampled surfaces for instance.
275  */
276 void
util_clear_depth_stencil(struct pipe_context * pipe,struct pipe_surface * dst,unsigned clear_flags,double depth,unsigned stencil,unsigned dstx,unsigned dsty,unsigned width,unsigned height)277 util_clear_depth_stencil(struct pipe_context *pipe,
278                          struct pipe_surface *dst,
279                          unsigned clear_flags,
280                          double depth,
281                          unsigned stencil,
282                          unsigned dstx, unsigned dsty,
283                          unsigned width, unsigned height)
284 {
285    struct pipe_transfer *dst_trans;
286    ubyte *dst_map;
287    boolean need_rmw = FALSE;
288 
289    if ((clear_flags & PIPE_CLEAR_DEPTHSTENCIL) &&
290        ((clear_flags & PIPE_CLEAR_DEPTHSTENCIL) != PIPE_CLEAR_DEPTHSTENCIL) &&
291        util_format_is_depth_and_stencil(dst->format))
292       need_rmw = TRUE;
293 
294    assert(dst->texture);
295    if (!dst->texture)
296       return;
297    dst_trans = pipe_get_transfer(pipe,
298                                  dst->texture,
299                                  dst->u.tex.level,
300                                  dst->u.tex.first_layer,
301                                  (need_rmw ? PIPE_TRANSFER_READ_WRITE :
302                                      PIPE_TRANSFER_WRITE),
303                                  dstx, dsty, width, height);
304 
305    dst_map = pipe->transfer_map(pipe, dst_trans);
306 
307    assert(dst_map);
308 
309    if (dst_map) {
310       unsigned dst_stride = dst_trans->stride;
311       unsigned zstencil = util_pack_z_stencil(dst->texture->format, depth, stencil);
312       unsigned i, j;
313       assert(dst_trans->stride > 0);
314 
315       switch (util_format_get_blocksize(dst->format)) {
316       case 1:
317          assert(dst->format == PIPE_FORMAT_S8_UINT);
318          if(dst_stride == width)
319             memset(dst_map, (ubyte) zstencil, height * width);
320          else {
321             for (i = 0; i < height; i++) {
322                memset(dst_map, (ubyte) zstencil, width);
323                dst_map += dst_stride;
324             }
325          }
326          break;
327       case 2:
328          assert(dst->format == PIPE_FORMAT_Z16_UNORM);
329          for (i = 0; i < height; i++) {
330             uint16_t *row = (uint16_t *)dst_map;
331             for (j = 0; j < width; j++)
332                *row++ = (uint16_t) zstencil;
333             dst_map += dst_stride;
334             }
335          break;
336       case 4:
337          if (!need_rmw) {
338             for (i = 0; i < height; i++) {
339                uint32_t *row = (uint32_t *)dst_map;
340                for (j = 0; j < width; j++)
341                   *row++ = zstencil;
342                dst_map += dst_stride;
343             }
344          }
345          else {
346             uint32_t dst_mask;
347             if (dst->format == PIPE_FORMAT_Z24_UNORM_S8_UINT)
348                dst_mask = 0xffffff00;
349             else {
350                assert(dst->format == PIPE_FORMAT_S8_UINT_Z24_UNORM);
351                dst_mask = 0xffffff;
352             }
353             if (clear_flags & PIPE_CLEAR_DEPTH)
354                dst_mask = ~dst_mask;
355             for (i = 0; i < height; i++) {
356                uint32_t *row = (uint32_t *)dst_map;
357                for (j = 0; j < width; j++) {
358                   uint32_t tmp = *row & dst_mask;
359                   *row++ = tmp | (zstencil & ~dst_mask);
360                }
361                dst_map += dst_stride;
362             }
363          }
364          break;
365       case 8:
366       {
367          uint64_t zstencil = util_pack64_z_stencil(dst->texture->format,
368                                                    depth, stencil);
369 
370          assert(dst->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT);
371 
372          if (!need_rmw) {
373             for (i = 0; i < height; i++) {
374                uint64_t *row = (uint64_t *)dst_map;
375                for (j = 0; j < width; j++)
376                   *row++ = zstencil;
377                dst_map += dst_stride;
378             }
379          }
380          else {
381             uint64_t src_mask;
382 
383             if (clear_flags & PIPE_CLEAR_DEPTH)
384                src_mask = 0x00000000ffffffffull;
385             else
386                src_mask = 0x000000ff00000000ull;
387 
388             for (i = 0; i < height; i++) {
389                uint64_t *row = (uint64_t *)dst_map;
390                for (j = 0; j < width; j++) {
391                   uint64_t tmp = *row & ~src_mask;
392                   *row++ = tmp | (zstencil & src_mask);
393                }
394                dst_map += dst_stride;
395             }
396          }
397          break;
398       }
399       default:
400          assert(0);
401          break;
402       }
403    }
404 
405    pipe->transfer_unmap(pipe, dst_trans);
406    pipe->transfer_destroy(pipe, dst_trans);
407 }
408