1848b8605Smrg/**************************************************************************
2848b8605Smrg *
3848b8605Smrg * Copyright 2009 VMware, Inc.  All Rights Reserved.
4848b8605Smrg *
5848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
6848b8605Smrg * copy of this software and associated documentation files (the
7848b8605Smrg * "Software"), to deal in the Software without restriction, including
8848b8605Smrg * without limitation the rights to use, copy, modify, merge, publish,
9848b8605Smrg * distribute, sub license, and/or sell copies of the Software, and to
10848b8605Smrg * permit persons to whom the Software is furnished to do so, subject to
11848b8605Smrg * the following conditions:
12848b8605Smrg *
13848b8605Smrg * The above copyright notice and this permission notice (including the
14848b8605Smrg * next paragraph) shall be included in all copies or substantial portions
15848b8605Smrg * of the Software.
16848b8605Smrg *
17848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19848b8605Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20848b8605Smrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21848b8605Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22848b8605Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23848b8605Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24848b8605Smrg *
25848b8605Smrg **************************************************************************/
26848b8605Smrg
27848b8605Smrg/**
28848b8605Smrg * @file
29848b8605Smrg * Surface utility functions.
30848b8605Smrg *
31848b8605Smrg * @author Brian Paul
32848b8605Smrg */
33848b8605Smrg
34848b8605Smrg
35848b8605Smrg#include "pipe/p_defines.h"
36848b8605Smrg#include "pipe/p_screen.h"
37848b8605Smrg#include "pipe/p_state.h"
38848b8605Smrg
39848b8605Smrg#include "util/u_format.h"
40848b8605Smrg#include "util/u_inlines.h"
41848b8605Smrg#include "util/u_rect.h"
42848b8605Smrg#include "util/u_surface.h"
43848b8605Smrg#include "util/u_pack_color.h"
44848b8605Smrg
45848b8605Smrg
46848b8605Smrg/**
47848b8605Smrg * Initialize a pipe_surface object.  'view' is considered to have
48848b8605Smrg * uninitialized contents.
49848b8605Smrg */
50848b8605Smrgvoid
51848b8605Smrgu_surface_default_template(struct pipe_surface *surf,
52848b8605Smrg                           const struct pipe_resource *texture)
53848b8605Smrg{
54848b8605Smrg   memset(surf, 0, sizeof(*surf));
55848b8605Smrg
56848b8605Smrg   surf->format = texture->format;
57848b8605Smrg}
58848b8605Smrg
59848b8605Smrg
60848b8605Smrg/**
61848b8605Smrg * Copy 2D rect from one place to another.
62848b8605Smrg * Position and sizes are in pixels.
63848b8605Smrg * src_stride may be negative to do vertical flip of pixels from source.
64848b8605Smrg */
65848b8605Smrgvoid
66848b8605Smrgutil_copy_rect(ubyte * dst,
67848b8605Smrg               enum pipe_format format,
68848b8605Smrg               unsigned dst_stride,
69848b8605Smrg               unsigned dst_x,
70848b8605Smrg               unsigned dst_y,
71848b8605Smrg               unsigned width,
72848b8605Smrg               unsigned height,
73848b8605Smrg               const ubyte * src,
74848b8605Smrg               int src_stride,
75848b8605Smrg               unsigned src_x,
76848b8605Smrg               unsigned src_y)
77848b8605Smrg{
78848b8605Smrg   unsigned i;
79848b8605Smrg   int src_stride_pos = src_stride < 0 ? -src_stride : src_stride;
80848b8605Smrg   int blocksize = util_format_get_blocksize(format);
81848b8605Smrg   int blockwidth = util_format_get_blockwidth(format);
82848b8605Smrg   int blockheight = util_format_get_blockheight(format);
83848b8605Smrg
84848b8605Smrg   assert(blocksize > 0);
85848b8605Smrg   assert(blockwidth > 0);
86848b8605Smrg   assert(blockheight > 0);
87848b8605Smrg
88848b8605Smrg   dst_x /= blockwidth;
89848b8605Smrg   dst_y /= blockheight;
90848b8605Smrg   width = (width + blockwidth - 1)/blockwidth;
91848b8605Smrg   height = (height + blockheight - 1)/blockheight;
92848b8605Smrg   src_x /= blockwidth;
93848b8605Smrg   src_y /= blockheight;
94848b8605Smrg
95848b8605Smrg   dst += dst_x * blocksize;
96848b8605Smrg   src += src_x * blocksize;
97848b8605Smrg   dst += dst_y * dst_stride;
98848b8605Smrg   src += src_y * src_stride_pos;
99848b8605Smrg   width *= blocksize;
100848b8605Smrg
101b8e80941Smrg   if (width == dst_stride && width == (unsigned)src_stride)
102848b8605Smrg      memcpy(dst, src, height * width);
103848b8605Smrg   else {
104848b8605Smrg      for (i = 0; i < height; i++) {
105848b8605Smrg         memcpy(dst, src, width);
106848b8605Smrg         dst += dst_stride;
107848b8605Smrg         src += src_stride;
108848b8605Smrg      }
109848b8605Smrg   }
110848b8605Smrg}
111848b8605Smrg
112848b8605Smrg
113848b8605Smrg/**
114848b8605Smrg * Copy 3D box from one place to another.
115848b8605Smrg * Position and sizes are in pixels.
116848b8605Smrg */
117848b8605Smrgvoid
118848b8605Smrgutil_copy_box(ubyte * dst,
119848b8605Smrg              enum pipe_format format,
120848b8605Smrg              unsigned dst_stride, unsigned dst_slice_stride,
121848b8605Smrg              unsigned dst_x, unsigned dst_y, unsigned dst_z,
122848b8605Smrg              unsigned width, unsigned height, unsigned depth,
123848b8605Smrg              const ubyte * src,
124848b8605Smrg              int src_stride, unsigned src_slice_stride,
125848b8605Smrg              unsigned src_x, unsigned src_y, unsigned src_z)
126848b8605Smrg{
127848b8605Smrg   unsigned z;
128848b8605Smrg   dst += dst_z * dst_slice_stride;
129848b8605Smrg   src += src_z * src_slice_stride;
130848b8605Smrg   for (z = 0; z < depth; ++z) {
131848b8605Smrg      util_copy_rect(dst,
132848b8605Smrg                     format,
133848b8605Smrg                     dst_stride,
134848b8605Smrg                     dst_x, dst_y,
135848b8605Smrg                     width, height,
136848b8605Smrg                     src,
137848b8605Smrg                     src_stride,
138848b8605Smrg                     src_x, src_y);
139848b8605Smrg
140848b8605Smrg      dst += dst_slice_stride;
141848b8605Smrg      src += src_slice_stride;
142848b8605Smrg   }
143848b8605Smrg}
144848b8605Smrg
145848b8605Smrg
146848b8605Smrgvoid
147848b8605Smrgutil_fill_rect(ubyte * dst,
148848b8605Smrg               enum pipe_format format,
149848b8605Smrg               unsigned dst_stride,
150848b8605Smrg               unsigned dst_x,
151848b8605Smrg               unsigned dst_y,
152848b8605Smrg               unsigned width,
153848b8605Smrg               unsigned height,
154848b8605Smrg               union util_color *uc)
155848b8605Smrg{
156848b8605Smrg   const struct util_format_description *desc = util_format_description(format);
157848b8605Smrg   unsigned i, j;
158848b8605Smrg   unsigned width_size;
159848b8605Smrg   int blocksize = desc->block.bits / 8;
160848b8605Smrg   int blockwidth = desc->block.width;
161848b8605Smrg   int blockheight = desc->block.height;
162848b8605Smrg
163848b8605Smrg   assert(blocksize > 0);
164848b8605Smrg   assert(blockwidth > 0);
165848b8605Smrg   assert(blockheight > 0);
166848b8605Smrg
167848b8605Smrg   dst_x /= blockwidth;
168848b8605Smrg   dst_y /= blockheight;
169848b8605Smrg   width = (width + blockwidth - 1)/blockwidth;
170848b8605Smrg   height = (height + blockheight - 1)/blockheight;
171848b8605Smrg
172848b8605Smrg   dst += dst_x * blocksize;
173848b8605Smrg   dst += dst_y * dst_stride;
174848b8605Smrg   width_size = width * blocksize;
175848b8605Smrg
176848b8605Smrg   switch (blocksize) {
177848b8605Smrg   case 1:
178848b8605Smrg      if(dst_stride == width_size)
179848b8605Smrg         memset(dst, uc->ub, height * width_size);
180848b8605Smrg      else {
181848b8605Smrg         for (i = 0; i < height; i++) {
182848b8605Smrg            memset(dst, uc->ub, width_size);
183848b8605Smrg            dst += dst_stride;
184848b8605Smrg         }
185848b8605Smrg      }
186848b8605Smrg      break;
187848b8605Smrg   case 2:
188848b8605Smrg      for (i = 0; i < height; i++) {
189848b8605Smrg         uint16_t *row = (uint16_t *)dst;
190848b8605Smrg         for (j = 0; j < width; j++)
191848b8605Smrg            *row++ = uc->us;
192848b8605Smrg         dst += dst_stride;
193848b8605Smrg      }
194848b8605Smrg      break;
195848b8605Smrg   case 4:
196848b8605Smrg      for (i = 0; i < height; i++) {
197848b8605Smrg         uint32_t *row = (uint32_t *)dst;
198848b8605Smrg         for (j = 0; j < width; j++)
199848b8605Smrg            *row++ = uc->ui[0];
200848b8605Smrg         dst += dst_stride;
201848b8605Smrg      }
202848b8605Smrg      break;
203848b8605Smrg   default:
204848b8605Smrg      for (i = 0; i < height; i++) {
205848b8605Smrg         ubyte *row = dst;
206848b8605Smrg         for (j = 0; j < width; j++) {
207848b8605Smrg            memcpy(row, uc, blocksize);
208848b8605Smrg            row += blocksize;
209848b8605Smrg         }
210848b8605Smrg         dst += dst_stride;
211848b8605Smrg      }
212848b8605Smrg      break;
213848b8605Smrg   }
214848b8605Smrg}
215848b8605Smrg
216848b8605Smrg
217848b8605Smrgvoid
218848b8605Smrgutil_fill_box(ubyte * dst,
219848b8605Smrg              enum pipe_format format,
220848b8605Smrg              unsigned stride,
221848b8605Smrg              unsigned layer_stride,
222848b8605Smrg              unsigned x,
223848b8605Smrg              unsigned y,
224848b8605Smrg              unsigned z,
225848b8605Smrg              unsigned width,
226848b8605Smrg              unsigned height,
227848b8605Smrg              unsigned depth,
228848b8605Smrg              union util_color *uc)
229848b8605Smrg{
230848b8605Smrg   unsigned layer;
231848b8605Smrg   dst += z * layer_stride;
232848b8605Smrg   for (layer = z; layer < depth; layer++) {
233848b8605Smrg      util_fill_rect(dst, format,
234848b8605Smrg                     stride,
235848b8605Smrg                     x, y, width, height, uc);
236848b8605Smrg      dst += layer_stride;
237848b8605Smrg   }
238848b8605Smrg}
239848b8605Smrg
240848b8605Smrg
241848b8605Smrg/**
242848b8605Smrg * Fallback function for pipe->resource_copy_region().
243b8e80941Smrg * We support copying between different formats (including compressed/
244b8e80941Smrg * uncompressed) if the bytes per block or pixel matches.  If copying
245b8e80941Smrg * compressed -> uncompressed, the dst region is reduced by the block
246b8e80941Smrg * width, height.  If copying uncompressed -> compressed, the dest region
247b8e80941Smrg * is expanded by the block width, height.  See GL_ARB_copy_image.
248848b8605Smrg * Note: (X,Y)=(0,0) is always the upper-left corner.
249848b8605Smrg */
250848b8605Smrgvoid
251848b8605Smrgutil_resource_copy_region(struct pipe_context *pipe,
252848b8605Smrg                          struct pipe_resource *dst,
253848b8605Smrg                          unsigned dst_level,
254848b8605Smrg                          unsigned dst_x, unsigned dst_y, unsigned dst_z,
255848b8605Smrg                          struct pipe_resource *src,
256848b8605Smrg                          unsigned src_level,
257b8e80941Smrg                          const struct pipe_box *src_box_in)
258848b8605Smrg{
259848b8605Smrg   struct pipe_transfer *src_trans, *dst_trans;
260848b8605Smrg   uint8_t *dst_map;
261848b8605Smrg   const uint8_t *src_map;
262b8e80941Smrg   enum pipe_format src_format;
263b8e80941Smrg   enum pipe_format dst_format;
264b8e80941Smrg   struct pipe_box src_box, dst_box;
265b8e80941Smrg   unsigned src_bs, dst_bs, src_bw, dst_bw, src_bh, dst_bh;
266848b8605Smrg
267848b8605Smrg   assert(src && dst);
268848b8605Smrg   if (!src || !dst)
269848b8605Smrg      return;
270848b8605Smrg
271848b8605Smrg   assert((src->target == PIPE_BUFFER && dst->target == PIPE_BUFFER) ||
272848b8605Smrg          (src->target != PIPE_BUFFER && dst->target != PIPE_BUFFER));
273848b8605Smrg
274848b8605Smrg   src_format = src->format;
275848b8605Smrg   dst_format = dst->format;
276848b8605Smrg
277b8e80941Smrg   /* init src box */
278b8e80941Smrg   src_box = *src_box_in;
279b8e80941Smrg
280b8e80941Smrg   /* init dst box */
281b8e80941Smrg   dst_box.x = dst_x;
282b8e80941Smrg   dst_box.y = dst_y;
283b8e80941Smrg   dst_box.z = dst_z;
284b8e80941Smrg   dst_box.width  = src_box.width;
285b8e80941Smrg   dst_box.height = src_box.height;
286b8e80941Smrg   dst_box.depth  = src_box.depth;
287b8e80941Smrg
288b8e80941Smrg   src_bs = util_format_get_blocksize(src_format);
289b8e80941Smrg   src_bw = util_format_get_blockwidth(src_format);
290b8e80941Smrg   src_bh = util_format_get_blockheight(src_format);
291b8e80941Smrg   dst_bs = util_format_get_blocksize(dst_format);
292b8e80941Smrg   dst_bw = util_format_get_blockwidth(dst_format);
293b8e80941Smrg   dst_bh = util_format_get_blockheight(dst_format);
294b8e80941Smrg
295b8e80941Smrg   /* Note: all box positions and sizes are in pixels */
296b8e80941Smrg   if (src_bw > 1 && dst_bw == 1) {
297b8e80941Smrg      /* Copy from compressed to uncompressed.
298b8e80941Smrg       * Shrink dest box by the src block size.
299b8e80941Smrg       */
300b8e80941Smrg      dst_box.width /= src_bw;
301b8e80941Smrg      dst_box.height /= src_bh;
302b8e80941Smrg   }
303b8e80941Smrg   else if (src_bw == 1 && dst_bw > 1) {
304b8e80941Smrg      /* Copy from uncompressed to compressed.
305b8e80941Smrg       * Expand dest box by the dest block size.
306b8e80941Smrg       */
307b8e80941Smrg      dst_box.width *= dst_bw;
308b8e80941Smrg      dst_box.height *= dst_bh;
309b8e80941Smrg   }
310b8e80941Smrg   else {
311b8e80941Smrg      /* compressed -> compressed or uncompressed -> uncompressed copy */
312b8e80941Smrg      assert(src_bw == dst_bw);
313b8e80941Smrg      assert(src_bh == dst_bh);
314b8e80941Smrg   }
315b8e80941Smrg
316b8e80941Smrg   assert(src_bs == dst_bs);
317b8e80941Smrg   if (src_bs != dst_bs) {
318b8e80941Smrg      /* This can happen if we fail to do format checking before hand.
319b8e80941Smrg       * Don't crash below.
320b8e80941Smrg       */
321b8e80941Smrg      return;
322b8e80941Smrg   }
323b8e80941Smrg
324b8e80941Smrg   /* check that region boxes are block aligned */
325b8e80941Smrg   assert(src_box.x % src_bw == 0);
326b8e80941Smrg   assert(src_box.y % src_bh == 0);
327b8e80941Smrg   assert(dst_box.x % dst_bw == 0);
328b8e80941Smrg   assert(dst_box.y % dst_bh == 0);
329b8e80941Smrg
330b8e80941Smrg   /* check that region boxes are not out of bounds */
331b8e80941Smrg   assert(src_box.x + src_box.width <= (int)u_minify(src->width0, src_level));
332b8e80941Smrg   assert(src_box.y + src_box.height <= (int)u_minify(src->height0, src_level));
333b8e80941Smrg   assert(dst_box.x + dst_box.width <= (int)u_minify(dst->width0, dst_level));
334b8e80941Smrg   assert(dst_box.y + dst_box.height <= (int)u_minify(dst->height0, dst_level));
335b8e80941Smrg
336b8e80941Smrg   /* check that total number of src, dest bytes match */
337b8e80941Smrg   assert((src_box.width / src_bw) * (src_box.height / src_bh) * src_bs ==
338b8e80941Smrg          (dst_box.width / dst_bw) * (dst_box.height / dst_bh) * dst_bs);
339848b8605Smrg
340848b8605Smrg   src_map = pipe->transfer_map(pipe,
341848b8605Smrg                                src,
342848b8605Smrg                                src_level,
343848b8605Smrg                                PIPE_TRANSFER_READ,
344b8e80941Smrg                                &src_box, &src_trans);
345848b8605Smrg   assert(src_map);
346848b8605Smrg   if (!src_map) {
347848b8605Smrg      goto no_src_map;
348848b8605Smrg   }
349848b8605Smrg
350848b8605Smrg   dst_map = pipe->transfer_map(pipe,
351848b8605Smrg                                dst,
352848b8605Smrg                                dst_level,
353b8e80941Smrg                                PIPE_TRANSFER_WRITE |
354b8e80941Smrg                                PIPE_TRANSFER_DISCARD_RANGE, &dst_box,
355b8e80941Smrg                                &dst_trans);
356848b8605Smrg   assert(dst_map);
357848b8605Smrg   if (!dst_map) {
358848b8605Smrg      goto no_dst_map;
359848b8605Smrg   }
360848b8605Smrg
361848b8605Smrg   if (dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER) {
362b8e80941Smrg      assert(src_box.height == 1);
363b8e80941Smrg      assert(src_box.depth == 1);
364b8e80941Smrg      memcpy(dst_map, src_map, src_box.width);
365848b8605Smrg   } else {
366848b8605Smrg      util_copy_box(dst_map,
367b8e80941Smrg                    src_format,
368848b8605Smrg                    dst_trans->stride, dst_trans->layer_stride,
369848b8605Smrg                    0, 0, 0,
370b8e80941Smrg                    src_box.width, src_box.height, src_box.depth,
371848b8605Smrg                    src_map,
372848b8605Smrg                    src_trans->stride, src_trans->layer_stride,
373848b8605Smrg                    0, 0, 0);
374848b8605Smrg   }
375848b8605Smrg
376848b8605Smrg   pipe->transfer_unmap(pipe, dst_trans);
377848b8605Smrgno_dst_map:
378848b8605Smrg   pipe->transfer_unmap(pipe, src_trans);
379848b8605Smrgno_src_map:
380848b8605Smrg   ;
381848b8605Smrg}
382848b8605Smrg
383b8e80941Smrgstatic void
384b8e80941Smrgutil_clear_color_texture_helper(struct pipe_transfer *dst_trans,
385b8e80941Smrg                                ubyte *dst_map,
386b8e80941Smrg                                enum pipe_format format,
387b8e80941Smrg                                const union pipe_color_union *color,
388b8e80941Smrg                                unsigned width, unsigned height, unsigned depth)
389b8e80941Smrg{
390b8e80941Smrg   union util_color uc;
391b8e80941Smrg
392b8e80941Smrg   assert(dst_trans->stride > 0);
393b8e80941Smrg
394b8e80941Smrg   if (util_format_is_pure_integer(format)) {
395b8e80941Smrg      /*
396b8e80941Smrg       * We expect int/uint clear values here, though some APIs
397b8e80941Smrg       * might disagree (but in any case util_pack_color()
398b8e80941Smrg       * couldn't handle it)...
399b8e80941Smrg       */
400b8e80941Smrg      if (util_format_is_pure_sint(format)) {
401b8e80941Smrg         util_format_write_4i(format, color->i, 0, &uc, 0, 0, 0, 1, 1);
402b8e80941Smrg      } else {
403b8e80941Smrg         assert(util_format_is_pure_uint(format));
404b8e80941Smrg         util_format_write_4ui(format, color->ui, 0, &uc, 0, 0, 0, 1, 1);
405b8e80941Smrg      }
406b8e80941Smrg   } else {
407b8e80941Smrg      util_pack_color(color->f, format, &uc);
408b8e80941Smrg   }
409b8e80941Smrg
410b8e80941Smrg   util_fill_box(dst_map, format,
411b8e80941Smrg                 dst_trans->stride, dst_trans->layer_stride,
412b8e80941Smrg                 0, 0, 0, width, height, depth, &uc);
413b8e80941Smrg}
414b8e80941Smrg
415b8e80941Smrgstatic void
416b8e80941Smrgutil_clear_color_texture(struct pipe_context *pipe,
417b8e80941Smrg                         struct pipe_resource *texture,
418b8e80941Smrg                         enum pipe_format format,
419b8e80941Smrg                         const union pipe_color_union *color,
420b8e80941Smrg                         unsigned level,
421b8e80941Smrg                         unsigned dstx, unsigned dsty, unsigned dstz,
422b8e80941Smrg                         unsigned width, unsigned height, unsigned depth)
423b8e80941Smrg{
424b8e80941Smrg   struct pipe_transfer *dst_trans;
425b8e80941Smrg   ubyte *dst_map;
426b8e80941Smrg
427b8e80941Smrg   dst_map = pipe_transfer_map_3d(pipe,
428b8e80941Smrg                                  texture,
429b8e80941Smrg                                  level,
430b8e80941Smrg                                  PIPE_TRANSFER_WRITE,
431b8e80941Smrg                                  dstx, dsty, dstz,
432b8e80941Smrg                                  width, height, depth,
433b8e80941Smrg                                  &dst_trans);
434b8e80941Smrg   if (!dst_map)
435b8e80941Smrg      return;
436b8e80941Smrg
437b8e80941Smrg   if (dst_trans->stride > 0) {
438b8e80941Smrg      util_clear_color_texture_helper(dst_trans, dst_map, format, color,
439b8e80941Smrg                                      width, height, depth);
440b8e80941Smrg   }
441b8e80941Smrg   pipe->transfer_unmap(pipe, dst_trans);
442b8e80941Smrg}
443848b8605Smrg
444848b8605Smrg
445848b8605Smrg#define UBYTE_TO_USHORT(B) ((B) | ((B) << 8))
446848b8605Smrg
447848b8605Smrg
448848b8605Smrg/**
449848b8605Smrg * Fallback for pipe->clear_render_target() function.
450848b8605Smrg * XXX this looks too hackish to be really useful.
451848b8605Smrg * cpp > 4 looks like a gross hack at best...
452848b8605Smrg * Plus can't use these transfer fallbacks when clearing
453848b8605Smrg * multisampled surfaces for instance.
454848b8605Smrg * Clears all bound layers.
455848b8605Smrg */
456848b8605Smrgvoid
457848b8605Smrgutil_clear_render_target(struct pipe_context *pipe,
458848b8605Smrg                         struct pipe_surface *dst,
459848b8605Smrg                         const union pipe_color_union *color,
460848b8605Smrg                         unsigned dstx, unsigned dsty,
461848b8605Smrg                         unsigned width, unsigned height)
462848b8605Smrg{
463848b8605Smrg   struct pipe_transfer *dst_trans;
464848b8605Smrg   ubyte *dst_map;
465848b8605Smrg
466848b8605Smrg   assert(dst->texture);
467848b8605Smrg   if (!dst->texture)
468848b8605Smrg      return;
469848b8605Smrg
470848b8605Smrg   if (dst->texture->target == PIPE_BUFFER) {
471848b8605Smrg      /*
472848b8605Smrg       * The fill naturally works on the surface format, however
473848b8605Smrg       * the transfer uses resource format which is just bytes for buffers.
474848b8605Smrg       */
475848b8605Smrg      unsigned dx, w;
476848b8605Smrg      unsigned pixstride = util_format_get_blocksize(dst->format);
477848b8605Smrg      dx = (dst->u.buf.first_element + dstx) * pixstride;
478848b8605Smrg      w = width * pixstride;
479848b8605Smrg      dst_map = pipe_transfer_map(pipe,
480848b8605Smrg                                  dst->texture,
481848b8605Smrg                                  0, 0,
482848b8605Smrg                                  PIPE_TRANSFER_WRITE,
483848b8605Smrg                                  dx, 0, w, 1,
484848b8605Smrg                                  &dst_trans);
485b8e80941Smrg      if (dst_map) {
486b8e80941Smrg         util_clear_color_texture_helper(dst_trans, dst_map, dst->format,
487b8e80941Smrg                                         color, width, height, 1);
488b8e80941Smrg         pipe->transfer_unmap(pipe, dst_trans);
489b8e80941Smrg      }
490848b8605Smrg   }
491848b8605Smrg   else {
492b8e80941Smrg      unsigned depth = dst->u.tex.last_layer - dst->u.tex.first_layer + 1;
493b8e80941Smrg      util_clear_color_texture(pipe, dst->texture, dst->format, color,
494b8e80941Smrg                               dst->u.tex.level, dstx, dsty,
495b8e80941Smrg                               dst->u.tex.first_layer, width, height, depth);
496848b8605Smrg   }
497b8e80941Smrg}
498b8e80941Smrg
499b8e80941Smrgstatic void
500b8e80941Smrgutil_clear_depth_stencil_texture(struct pipe_context *pipe,
501b8e80941Smrg                                 struct pipe_resource *texture,
502b8e80941Smrg                                 enum pipe_format format,
503b8e80941Smrg                                 unsigned clear_flags,
504b8e80941Smrg                                 uint64_t zstencil, unsigned level,
505b8e80941Smrg                                 unsigned dstx, unsigned dsty, unsigned dstz,
506b8e80941Smrg                                 unsigned width, unsigned height, unsigned depth)
507b8e80941Smrg{
508b8e80941Smrg   struct pipe_transfer *dst_trans;
509b8e80941Smrg   ubyte *dst_map;
510b8e80941Smrg   boolean need_rmw = FALSE;
511b8e80941Smrg   unsigned dst_stride;
512b8e80941Smrg   ubyte *dst_layer;
513b8e80941Smrg   unsigned i, j, layer;
514848b8605Smrg
515b8e80941Smrg   if ((clear_flags & PIPE_CLEAR_DEPTHSTENCIL) &&
516b8e80941Smrg       ((clear_flags & PIPE_CLEAR_DEPTHSTENCIL) != PIPE_CLEAR_DEPTHSTENCIL) &&
517b8e80941Smrg       util_format_is_depth_and_stencil(format))
518b8e80941Smrg      need_rmw = TRUE;
519b8e80941Smrg
520b8e80941Smrg   dst_map = pipe_transfer_map_3d(pipe,
521b8e80941Smrg                                  texture,
522b8e80941Smrg                                  level,
523b8e80941Smrg                                  (need_rmw ? PIPE_TRANSFER_READ_WRITE :
524b8e80941Smrg                                              PIPE_TRANSFER_WRITE),
525b8e80941Smrg                                  dstx, dsty, dstz,
526b8e80941Smrg                                  width, height, depth, &dst_trans);
527848b8605Smrg   assert(dst_map);
528b8e80941Smrg   if (!dst_map)
529b8e80941Smrg      return;
530848b8605Smrg
531b8e80941Smrg   dst_stride = dst_trans->stride;
532b8e80941Smrg   dst_layer = dst_map;
533b8e80941Smrg   assert(dst_trans->stride > 0);
534b8e80941Smrg
535b8e80941Smrg   for (layer = 0; layer < depth; layer++) {
536b8e80941Smrg      dst_map = dst_layer;
537b8e80941Smrg
538b8e80941Smrg      switch (util_format_get_blocksize(format)) {
539b8e80941Smrg      case 1:
540b8e80941Smrg         assert(format == PIPE_FORMAT_S8_UINT);
541b8e80941Smrg         if(dst_stride == width)
542b8e80941Smrg            memset(dst_map, (uint8_t) zstencil, height * width);
543b8e80941Smrg         else {
544b8e80941Smrg            for (i = 0; i < height; i++) {
545b8e80941Smrg               memset(dst_map, (uint8_t) zstencil, width);
546b8e80941Smrg               dst_map += dst_stride;
547b8e80941Smrg            }
548b8e80941Smrg         }
549b8e80941Smrg         break;
550b8e80941Smrg      case 2:
551b8e80941Smrg         assert(format == PIPE_FORMAT_Z16_UNORM);
552b8e80941Smrg         for (i = 0; i < height; i++) {
553b8e80941Smrg            uint16_t *row = (uint16_t *)dst_map;
554b8e80941Smrg            for (j = 0; j < width; j++)
555b8e80941Smrg               *row++ = (uint16_t) zstencil;
556b8e80941Smrg            dst_map += dst_stride;
557b8e80941Smrg            }
558b8e80941Smrg         break;
559b8e80941Smrg      case 4:
560b8e80941Smrg         if (!need_rmw) {
561b8e80941Smrg            for (i = 0; i < height; i++) {
562b8e80941Smrg               uint32_t *row = (uint32_t *)dst_map;
563b8e80941Smrg               for (j = 0; j < width; j++)
564b8e80941Smrg                  *row++ = (uint32_t) zstencil;
565b8e80941Smrg               dst_map += dst_stride;
566b8e80941Smrg            }
567b8e80941Smrg         }
568b8e80941Smrg         else {
569b8e80941Smrg            uint32_t dst_mask;
570b8e80941Smrg            if (format == PIPE_FORMAT_Z24_UNORM_S8_UINT)
571b8e80941Smrg               dst_mask = 0x00ffffff;
572b8e80941Smrg            else {
573b8e80941Smrg               assert(format == PIPE_FORMAT_S8_UINT_Z24_UNORM);
574b8e80941Smrg               dst_mask = 0xffffff00;
575b8e80941Smrg            }
576b8e80941Smrg            if (clear_flags & PIPE_CLEAR_DEPTH)
577b8e80941Smrg               dst_mask = ~dst_mask;
578b8e80941Smrg            for (i = 0; i < height; i++) {
579b8e80941Smrg               uint32_t *row = (uint32_t *)dst_map;
580b8e80941Smrg               for (j = 0; j < width; j++) {
581b8e80941Smrg                  uint32_t tmp = *row & dst_mask;
582b8e80941Smrg                  *row++ = tmp | ((uint32_t) zstencil & ~dst_mask);
583b8e80941Smrg               }
584b8e80941Smrg               dst_map += dst_stride;
585b8e80941Smrg            }
586b8e80941Smrg         }
587b8e80941Smrg         break;
588b8e80941Smrg      case 8:
589b8e80941Smrg         if (!need_rmw) {
590b8e80941Smrg            for (i = 0; i < height; i++) {
591b8e80941Smrg               uint64_t *row = (uint64_t *)dst_map;
592b8e80941Smrg               for (j = 0; j < width; j++)
593b8e80941Smrg                  *row++ = zstencil;
594b8e80941Smrg               dst_map += dst_stride;
595b8e80941Smrg            }
596848b8605Smrg         }
597848b8605Smrg         else {
598b8e80941Smrg            uint64_t src_mask;
599b8e80941Smrg
600b8e80941Smrg            if (clear_flags & PIPE_CLEAR_DEPTH)
601b8e80941Smrg               src_mask = 0x00000000ffffffffull;
602b8e80941Smrg            else
603b8e80941Smrg               src_mask = 0x000000ff00000000ull;
604b8e80941Smrg
605b8e80941Smrg            for (i = 0; i < height; i++) {
606b8e80941Smrg               uint64_t *row = (uint64_t *)dst_map;
607b8e80941Smrg               for (j = 0; j < width; j++) {
608b8e80941Smrg                  uint64_t tmp = *row & ~src_mask;
609b8e80941Smrg                  *row++ = tmp | (zstencil & src_mask);
610b8e80941Smrg               }
611b8e80941Smrg               dst_map += dst_stride;
612b8e80941Smrg            }
613848b8605Smrg         }
614b8e80941Smrg         break;
615b8e80941Smrg      default:
616b8e80941Smrg         assert(0);
617b8e80941Smrg         break;
618848b8605Smrg      }
619b8e80941Smrg      dst_layer += dst_trans->layer_stride;
620b8e80941Smrg   }
621b8e80941Smrg
622b8e80941Smrg   pipe->transfer_unmap(pipe, dst_trans);
623b8e80941Smrg}
624b8e80941Smrg
625b8e80941Smrg
626b8e80941Smrgvoid
627b8e80941Smrgutil_clear_texture(struct pipe_context *pipe,
628b8e80941Smrg                   struct pipe_resource *tex,
629b8e80941Smrg                   unsigned level,
630b8e80941Smrg                   const struct pipe_box *box,
631b8e80941Smrg                   const void *data)
632b8e80941Smrg{
633b8e80941Smrg   const struct util_format_description *desc =
634b8e80941Smrg          util_format_description(tex->format);
635b8e80941Smrg
636b8e80941Smrg   if (level > tex->last_level)
637b8e80941Smrg      return;
638b8e80941Smrg
639b8e80941Smrg   if (util_format_is_depth_or_stencil(tex->format)) {
640b8e80941Smrg      unsigned clear = 0;
641b8e80941Smrg      float depth = 0.0f;
642b8e80941Smrg      uint8_t stencil = 0;
643b8e80941Smrg      uint64_t zstencil;
644b8e80941Smrg
645b8e80941Smrg      if (util_format_has_depth(desc)) {
646b8e80941Smrg         clear |= PIPE_CLEAR_DEPTH;
647b8e80941Smrg         desc->unpack_z_float(&depth, 0, data, 0, 1, 1);
648848b8605Smrg      }
649848b8605Smrg
650b8e80941Smrg      if (util_format_has_stencil(desc)) {
651b8e80941Smrg         clear |= PIPE_CLEAR_STENCIL;
652b8e80941Smrg         desc->unpack_s_8uint(&stencil, 0, data, 0, 1, 1);
653b8e80941Smrg      }
654b8e80941Smrg
655b8e80941Smrg      zstencil = util_pack64_z_stencil(tex->format, depth, stencil);
656848b8605Smrg
657b8e80941Smrg      util_clear_depth_stencil_texture(pipe, tex, tex->format, clear, zstencil,
658b8e80941Smrg                                       level, box->x, box->y, box->z,
659b8e80941Smrg                                       box->width, box->height, box->depth);
660b8e80941Smrg   } else {
661b8e80941Smrg      union pipe_color_union color;
662b8e80941Smrg      if (util_format_is_pure_uint(tex->format))
663b8e80941Smrg         desc->unpack_rgba_uint(color.ui, 0, data, 0, 1, 1);
664b8e80941Smrg      else if (util_format_is_pure_sint(tex->format))
665b8e80941Smrg         desc->unpack_rgba_sint(color.i, 0, data, 0, 1, 1);
666b8e80941Smrg      else
667b8e80941Smrg         desc->unpack_rgba_float(color.f, 0, data, 0, 1, 1);
668b8e80941Smrg
669b8e80941Smrg      util_clear_color_texture(pipe, tex, tex->format, &color, level,
670b8e80941Smrg                               box->x, box->y, box->z,
671b8e80941Smrg                               box->width, box->height, box->depth);
672848b8605Smrg   }
673848b8605Smrg}
674848b8605Smrg
675b8e80941Smrg
676848b8605Smrg/**
677848b8605Smrg * Fallback for pipe->clear_stencil() function.
678848b8605Smrg * sw fallback doesn't look terribly useful here.
679848b8605Smrg * Plus can't use these transfer fallbacks when clearing
680848b8605Smrg * multisampled surfaces for instance.
681848b8605Smrg * Clears all bound layers.
682848b8605Smrg */
683848b8605Smrgvoid
684848b8605Smrgutil_clear_depth_stencil(struct pipe_context *pipe,
685848b8605Smrg                         struct pipe_surface *dst,
686848b8605Smrg                         unsigned clear_flags,
687848b8605Smrg                         double depth,
688848b8605Smrg                         unsigned stencil,
689848b8605Smrg                         unsigned dstx, unsigned dsty,
690848b8605Smrg                         unsigned width, unsigned height)
691848b8605Smrg{
692b8e80941Smrg   uint64_t zstencil;
693b8e80941Smrg   unsigned max_layer;
694848b8605Smrg
695848b8605Smrg   assert(dst->texture);
696848b8605Smrg   if (!dst->texture)
697848b8605Smrg      return;
698848b8605Smrg
699b8e80941Smrg   zstencil = util_pack64_z_stencil(dst->format, depth, stencil);
700848b8605Smrg   max_layer = dst->u.tex.last_layer - dst->u.tex.first_layer;
701b8e80941Smrg   util_clear_depth_stencil_texture(pipe, dst->texture, dst->format,
702b8e80941Smrg                                    clear_flags, zstencil, dst->u.tex.level,
703b8e80941Smrg                                    dstx, dsty, dst->u.tex.first_layer,
704b8e80941Smrg                                    width, height, max_layer + 1);
705848b8605Smrg}
706848b8605Smrg
707848b8605Smrg
708848b8605Smrg/* Return if the box is totally inside the resource.
709848b8605Smrg */
710848b8605Smrgstatic boolean
711848b8605Smrgis_box_inside_resource(const struct pipe_resource *res,
712848b8605Smrg                       const struct pipe_box *box,
713848b8605Smrg                       unsigned level)
714848b8605Smrg{
715848b8605Smrg   unsigned width = 1, height = 1, depth = 1;
716848b8605Smrg
717848b8605Smrg   switch (res->target) {
718848b8605Smrg   case PIPE_BUFFER:
719848b8605Smrg      width = res->width0;
720848b8605Smrg      height = 1;
721848b8605Smrg      depth = 1;
722848b8605Smrg      break;
723848b8605Smrg   case PIPE_TEXTURE_1D:
724848b8605Smrg      width = u_minify(res->width0, level);
725848b8605Smrg      height = 1;
726848b8605Smrg      depth = 1;
727848b8605Smrg      break;
728848b8605Smrg   case PIPE_TEXTURE_2D:
729848b8605Smrg   case PIPE_TEXTURE_RECT:
730848b8605Smrg      width = u_minify(res->width0, level);
731848b8605Smrg      height = u_minify(res->height0, level);
732848b8605Smrg      depth = 1;
733848b8605Smrg      break;
734848b8605Smrg   case PIPE_TEXTURE_3D:
735848b8605Smrg      width = u_minify(res->width0, level);
736848b8605Smrg      height = u_minify(res->height0, level);
737848b8605Smrg      depth = u_minify(res->depth0, level);
738848b8605Smrg      break;
739848b8605Smrg   case PIPE_TEXTURE_CUBE:
740848b8605Smrg      width = u_minify(res->width0, level);
741848b8605Smrg      height = u_minify(res->height0, level);
742848b8605Smrg      depth = 6;
743848b8605Smrg      break;
744848b8605Smrg   case PIPE_TEXTURE_1D_ARRAY:
745848b8605Smrg      width = u_minify(res->width0, level);
746848b8605Smrg      height = 1;
747848b8605Smrg      depth = res->array_size;
748848b8605Smrg      break;
749848b8605Smrg   case PIPE_TEXTURE_2D_ARRAY:
750848b8605Smrg      width = u_minify(res->width0, level);
751848b8605Smrg      height = u_minify(res->height0, level);
752848b8605Smrg      depth = res->array_size;
753848b8605Smrg      break;
754848b8605Smrg   case PIPE_TEXTURE_CUBE_ARRAY:
755848b8605Smrg      width = u_minify(res->width0, level);
756848b8605Smrg      height = u_minify(res->height0, level);
757848b8605Smrg      depth = res->array_size;
758848b8605Smrg      assert(res->array_size % 6 == 0);
759848b8605Smrg      break;
760b8e80941Smrg   case PIPE_MAX_TEXTURE_TYPES:
761b8e80941Smrg      break;
762848b8605Smrg   }
763848b8605Smrg
764848b8605Smrg   return box->x >= 0 &&
765848b8605Smrg          box->x + box->width <= (int) width &&
766848b8605Smrg          box->y >= 0 &&
767848b8605Smrg          box->y + box->height <= (int) height &&
768848b8605Smrg          box->z >= 0 &&
769848b8605Smrg          box->z + box->depth <= (int) depth;
770848b8605Smrg}
771848b8605Smrg
772848b8605Smrgstatic unsigned
773848b8605Smrgget_sample_count(const struct pipe_resource *res)
774848b8605Smrg{
775848b8605Smrg   return res->nr_samples ? res->nr_samples : 1;
776848b8605Smrg}
777848b8605Smrg
778b8e80941Smrg
779848b8605Smrg/**
780b8e80941Smrg * Check if a blit() command can be implemented with a resource_copy_region().
781b8e80941Smrg * If tight_format_check is true, only allow the resource_copy_region() if
782b8e80941Smrg * the blit src/dst formats are identical, ignoring the resource formats.
783b8e80941Smrg * Otherwise, check for format casting and compatibility.
784848b8605Smrg */
785848b8605Smrgboolean
786b8e80941Smrgutil_can_blit_via_copy_region(const struct pipe_blit_info *blit,
787b8e80941Smrg                              boolean tight_format_check)
788848b8605Smrg{
789b8e80941Smrg   const struct util_format_description *src_desc, *dst_desc;
790848b8605Smrg
791b8e80941Smrg   src_desc = util_format_description(blit->src.resource->format);
792b8e80941Smrg   dst_desc = util_format_description(blit->dst.resource->format);
793b8e80941Smrg
794b8e80941Smrg   if (tight_format_check) {
795b8e80941Smrg      /* no format conversions allowed */
796b8e80941Smrg      if (blit->src.format != blit->dst.format) {
797b8e80941Smrg         return FALSE;
798b8e80941Smrg      }
799b8e80941Smrg   }
800b8e80941Smrg   else {
801b8e80941Smrg      /* do loose format compatibility checking */
802b8e80941Smrg      if (blit->src.resource->format != blit->src.format ||
803b8e80941Smrg          blit->dst.resource->format != blit->dst.format ||
804b8e80941Smrg          !util_is_format_compatible(src_desc, dst_desc)) {
805b8e80941Smrg         return FALSE;
806b8e80941Smrg      }
807848b8605Smrg   }
808848b8605Smrg
809b8e80941Smrg   unsigned mask = util_format_get_mask(blit->dst.format);
810b8e80941Smrg
811b8e80941Smrg   /* No masks, no filtering, no scissor, no blending */
812848b8605Smrg   if ((blit->mask & mask) != mask ||
813848b8605Smrg       blit->filter != PIPE_TEX_FILTER_NEAREST ||
814b8e80941Smrg       blit->scissor_enable ||
815b8e80941Smrg       blit->num_window_rectangles > 0 ||
816b8e80941Smrg       blit->alpha_blend) {
817848b8605Smrg      return FALSE;
818848b8605Smrg   }
819848b8605Smrg
820b8e80941Smrg   /* Only the src box can have negative dims for flipping */
821b8e80941Smrg   assert(blit->dst.box.width >= 1);
822b8e80941Smrg   assert(blit->dst.box.height >= 1);
823b8e80941Smrg   assert(blit->dst.box.depth >= 1);
824848b8605Smrg
825b8e80941Smrg   /* No scaling or flipping */
826848b8605Smrg   if (blit->src.box.width != blit->dst.box.width ||
827848b8605Smrg       blit->src.box.height != blit->dst.box.height ||
828848b8605Smrg       blit->src.box.depth != blit->dst.box.depth) {
829848b8605Smrg      return FALSE;
830848b8605Smrg   }
831848b8605Smrg
832848b8605Smrg   /* No out-of-bounds access. */
833848b8605Smrg   if (!is_box_inside_resource(blit->src.resource, &blit->src.box,
834848b8605Smrg                               blit->src.level) ||
835848b8605Smrg       !is_box_inside_resource(blit->dst.resource, &blit->dst.box,
836848b8605Smrg                               blit->dst.level)) {
837848b8605Smrg      return FALSE;
838848b8605Smrg   }
839848b8605Smrg
840848b8605Smrg   /* Sample counts must match. */
841848b8605Smrg   if (get_sample_count(blit->src.resource) !=
842848b8605Smrg       get_sample_count(blit->dst.resource)) {
843848b8605Smrg      return FALSE;
844848b8605Smrg   }
845848b8605Smrg
846848b8605Smrg   return TRUE;
847848b8605Smrg}
848b8e80941Smrg
849b8e80941Smrg
850b8e80941Smrg/**
851b8e80941Smrg * Try to do a blit using resource_copy_region. The function calls
852b8e80941Smrg * resource_copy_region if the blit description is compatible with it.
853b8e80941Smrg *
854b8e80941Smrg * It returns TRUE if the blit was done using resource_copy_region.
855b8e80941Smrg *
856b8e80941Smrg * It returns FALSE otherwise and the caller must fall back to a more generic
857b8e80941Smrg * codepath for the blit operation. (e.g. by using u_blitter)
858b8e80941Smrg */
859b8e80941Smrgboolean
860b8e80941Smrgutil_try_blit_via_copy_region(struct pipe_context *ctx,
861b8e80941Smrg                              const struct pipe_blit_info *blit)
862b8e80941Smrg{
863b8e80941Smrg   if (util_can_blit_via_copy_region(blit, FALSE)) {
864b8e80941Smrg      ctx->resource_copy_region(ctx, blit->dst.resource, blit->dst.level,
865b8e80941Smrg                                blit->dst.box.x, blit->dst.box.y,
866b8e80941Smrg                                blit->dst.box.z,
867b8e80941Smrg                                blit->src.resource, blit->src.level,
868b8e80941Smrg                                &blit->src.box);
869b8e80941Smrg      return TRUE;
870b8e80941Smrg   }
871b8e80941Smrg   else {
872b8e80941Smrg      return FALSE;
873b8e80941Smrg   }
874b8e80941Smrg}
875