• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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