• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**********************************************************
2  * Copyright 2008-2009 VMware, Inc.  All rights reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation
6  * files (the "Software"), to deal in the Software without
7  * restriction, including without limitation the rights to use, copy,
8  * modify, merge, publish, distribute, sublicense, and/or sell copies
9  * of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  *
24  **********************************************************/
25 
26 #include "svga_context.h"
27 #include "svga_debug.h"
28 #include "svga_cmd.h"
29 #include "svga_format.h"
30 #include "svga_resource_buffer.h"
31 #include "svga_resource_texture.h"
32 #include "svga_surface.h"
33 
34 //#include "util/u_blit_sw.h"
35 #include "util/u_format.h"
36 #include "util/u_surface.h"
37 
38 #define FILE_DEBUG_FLAG DEBUG_BLIT
39 
40 
41 /**
42  * Copy an image between textures with the vgpu10 CopyRegion command.
43  */
44 static void
copy_region_vgpu10(struct svga_context * svga,struct pipe_resource * src_tex,unsigned src_x,unsigned src_y,unsigned src_z,unsigned src_level,unsigned src_face,struct pipe_resource * dst_tex,unsigned dst_x,unsigned dst_y,unsigned dst_z,unsigned dst_level,unsigned dst_face,unsigned width,unsigned height,unsigned depth)45 copy_region_vgpu10(struct svga_context *svga, struct pipe_resource *src_tex,
46                     unsigned src_x, unsigned src_y, unsigned src_z,
47                     unsigned src_level, unsigned src_face,
48                     struct pipe_resource *dst_tex,
49                     unsigned dst_x, unsigned dst_y, unsigned dst_z,
50                     unsigned dst_level, unsigned dst_face,
51                     unsigned width, unsigned height, unsigned depth)
52 {
53    enum pipe_error ret;
54    uint32 srcSubResource, dstSubResource;
55    struct svga_texture *dtex, *stex;
56    SVGA3dCopyBox box;
57 
58    stex = svga_texture(src_tex);
59    dtex = svga_texture(dst_tex);
60 
61    box.x = dst_x;
62    box.y = dst_y;
63    box.z = dst_z;
64    box.w = width;
65    box.h = height;
66    box.d = depth;
67    box.srcx = src_x;
68    box.srcy = src_y;
69    box.srcz = src_z;
70 
71    srcSubResource = src_face * (src_tex->last_level + 1) + src_level;
72    dstSubResource = dst_face * (dst_tex->last_level + 1) + dst_level;
73 
74    ret = SVGA3D_vgpu10_PredCopyRegion(svga->swc,
75                                       dtex->handle, dstSubResource,
76                                       stex->handle, srcSubResource, &box);
77    if (ret != PIPE_OK) {
78       svga_context_flush(svga, NULL);
79       ret = SVGA3D_vgpu10_PredCopyRegion(svga->swc,
80                                          dtex->handle, dstSubResource,
81                                          stex->handle, srcSubResource, &box);
82       assert(ret == PIPE_OK);
83    }
84 
85    /* Mark the texture subresource as defined. */
86    svga_define_texture_level(dtex, dst_face, dst_level);
87 
88    /* Mark the texture subresource as rendered-to. */
89    svga_set_texture_rendered_to(dtex, dst_face, dst_level);
90 }
91 
92 
93 /**
94  * For some texture types, we need to move the z (slice) coordinate
95  * to the layer value.  For example, to select the z=3 slice of a 2D ARRAY
96  * texture, we need to use layer=3 and set z=0.
97  */
98 static void
adjust_z_layer(enum pipe_texture_target target,int z_in,unsigned * layer_out,unsigned * z_out)99 adjust_z_layer(enum pipe_texture_target target,
100                int z_in, unsigned *layer_out, unsigned *z_out)
101 {
102    if (target == PIPE_TEXTURE_CUBE ||
103        target == PIPE_TEXTURE_2D_ARRAY ||
104        target == PIPE_TEXTURE_1D_ARRAY) {
105       *layer_out = z_in;
106       *z_out = 0;
107    }
108    else {
109       *layer_out = 0;
110       *z_out = z_in;
111    }
112 }
113 
114 
115 static void
svga_resource_copy_region(struct pipe_context * pipe,struct pipe_resource * dst_tex,unsigned dst_level,unsigned dstx,unsigned dsty,unsigned dstz,struct pipe_resource * src_tex,unsigned src_level,const struct pipe_box * src_box)116 svga_resource_copy_region(struct pipe_context *pipe,
117                           struct pipe_resource *dst_tex,
118                           unsigned dst_level,
119                           unsigned dstx, unsigned dsty, unsigned dstz,
120                           struct pipe_resource *src_tex,
121                           unsigned src_level,
122                           const struct pipe_box *src_box)
123 {
124    struct svga_context *svga = svga_context(pipe);
125    struct svga_texture *stex, *dtex;
126    unsigned dst_face_layer, dst_z, src_face_layer, src_z;
127 
128    /* Emit buffered drawing commands, and any back copies.
129     */
130    svga_surfaces_flush( svga );
131 
132    if (dst_tex->target == PIPE_BUFFER && src_tex->target == PIPE_BUFFER) {
133       /* can't copy within the same buffer, unfortunately */
134       if (svga_have_vgpu10(svga) && src_tex != dst_tex) {
135          enum pipe_error ret;
136          struct svga_winsys_surface *src_surf;
137          struct svga_winsys_surface *dst_surf;
138          struct svga_buffer *dbuffer = svga_buffer(dst_tex);
139 
140          src_surf = svga_buffer_handle(svga, src_tex);
141          dst_surf = svga_buffer_handle(svga, dst_tex);
142 
143          ret = SVGA3D_vgpu10_BufferCopy(svga->swc, src_surf, dst_surf,
144                                         src_box->x, dstx, src_box->width);
145          if (ret != PIPE_OK) {
146             svga_context_flush(svga, NULL);
147             ret = SVGA3D_vgpu10_BufferCopy(svga->swc, src_surf, dst_surf,
148                                            src_box->x, dstx, src_box->width);
149             assert(ret == PIPE_OK);
150          }
151 
152          dbuffer->dirty = TRUE;
153       }
154       else {
155          /* use map/memcpy fallback */
156          util_resource_copy_region(pipe, dst_tex, dst_level, dstx,
157                                    dsty, dstz, src_tex, src_level, src_box);
158       }
159       return;
160    }
161 
162    stex = svga_texture(src_tex);
163    dtex = svga_texture(dst_tex);
164 
165    adjust_z_layer(src_tex->target, src_box->z, &src_face_layer, &src_z);
166    adjust_z_layer(dst_tex->target, dstz, &dst_face_layer, &dst_z);
167 
168    if (svga_have_vgpu10(svga)) {
169       /* vgpu10 */
170       if (util_format_is_compressed(src_tex->format) ==
171           util_format_is_compressed(dst_tex->format) &&
172           stex->handle != dtex->handle &&
173           svga_resource_type(src_tex->target) ==
174           svga_resource_type(dst_tex->target) &&
175           stex->b.b.nr_samples == dtex->b.b.nr_samples) {
176          copy_region_vgpu10(svga,
177                             src_tex,
178                             src_box->x, src_box->y, src_z,
179                             src_level, src_face_layer,
180                             dst_tex,
181                             dstx, dsty, dst_z,
182                             dst_level, dst_face_layer,
183                             src_box->width, src_box->height, src_box->depth);
184       }
185       else {
186          util_resource_copy_region(pipe, dst_tex, dst_level, dstx, dsty, dstz,
187                                    src_tex, src_level, src_box);
188       }
189    }
190    else {
191       /* vgpu9 */
192       if (src_tex->format == dst_tex->format) {
193          svga_texture_copy_handle(svga,
194                                   stex->handle,
195                                   src_box->x, src_box->y, src_z,
196                                   src_level, src_face_layer,
197                                   dtex->handle,
198                                   dstx, dsty, dst_z,
199                                    dst_level, dst_face_layer,
200                                   src_box->width, src_box->height,
201                                   src_box->depth);
202       }
203       else {
204          util_resource_copy_region(pipe, dst_tex, dst_level, dstx, dsty, dstz,
205                                    src_tex, src_level, src_box);
206       }
207    }
208 
209    /* Mark the destination image as being defined */
210    svga_define_texture_level(dtex, dst_face_layer, dst_level);
211 }
212 
213 
214 /**
215  * Are the given pipe formats compatible, in terms of vgpu10's
216  * PredCopyRegion() command?
217  */
218 static bool
formats_compatible(const struct svga_screen * ss,enum pipe_format src_fmt,enum pipe_format dst_fmt)219 formats_compatible(const struct svga_screen *ss,
220                    enum pipe_format src_fmt,
221                    enum pipe_format dst_fmt)
222 {
223    SVGA3dSurfaceFormat src_svga_fmt, dst_svga_fmt;
224 
225    src_svga_fmt = svga_translate_format(ss, src_fmt, PIPE_BIND_SAMPLER_VIEW);
226    dst_svga_fmt = svga_translate_format(ss, dst_fmt, PIPE_BIND_SAMPLER_VIEW);
227 
228    src_svga_fmt = svga_typeless_format(src_svga_fmt);
229    dst_svga_fmt = svga_typeless_format(dst_svga_fmt);
230 
231    return src_svga_fmt == dst_svga_fmt;
232 }
233 
234 
235 /**
236  * The state tracker implements some resource copies with blits (for
237  * GL_ARB_copy_image).  This function checks if we should really do the blit
238  * with a VGPU10 CopyRegion command or software fallback (for incompatible
239  * src/dst formats).
240  */
241 static bool
can_blit_via_copy_region_vgpu10(struct svga_context * svga,const struct pipe_blit_info * blit_info)242 can_blit_via_copy_region_vgpu10(struct svga_context *svga,
243                                 const struct pipe_blit_info *blit_info)
244 {
245    struct svga_texture *dtex, *stex;
246 
247    if (!svga_have_vgpu10(svga))
248       return false;
249 
250    stex = svga_texture(blit_info->src.resource);
251    dtex = svga_texture(blit_info->dst.resource);
252 
253    /* can't copy within one resource */
254    if (stex->handle == dtex->handle)
255       return false;
256 
257    /* can't copy between different resource types */
258    if (svga_resource_type(blit_info->src.resource->target) !=
259        svga_resource_type(blit_info->dst.resource->target))
260       return false;
261 
262    /* check that the blit src/dst regions are same size, no flipping, etc. */
263    if (blit_info->src.box.width != blit_info->dst.box.width ||
264        blit_info->src.box.height != blit_info->dst.box.height)
265       return false;
266 
267    /* check that sample counts are the same */
268    if (stex->b.b.nr_samples != dtex->b.b.nr_samples)
269       return false;
270 
271    /* For depth+stencil formats, copy with mask != PIPE_MASK_ZS is not
272     * supported
273     */
274    if (util_format_is_depth_and_stencil(blit_info->src.format) &&
275       blit_info->mask != (PIPE_MASK_ZS))
276      return false;
277 
278    if (blit_info->alpha_blend ||
279        (svga->render_condition && blit_info->render_condition_enable) ||
280        blit_info->scissor_enable)
281       return false;
282 
283    return formats_compatible(svga_screen(svga->pipe.screen),
284                              blit_info->src.resource->format,
285                              blit_info->dst.resource->format);
286 }
287 
288 
289 /**
290  * A helper function to determine if the specified view format
291  * is compatible with the surface format.
292  * It is compatible if the view format is the same as the surface format,
293  * or the associated svga format for the surface is a typeless format, or
294  * the view format is an adjusted format for BGRX/BGRA resource.
295  */
296 static bool
is_view_format_compatible(enum pipe_format surf_fmt,SVGA3dSurfaceFormat surf_svga_fmt,enum pipe_format view_fmt)297 is_view_format_compatible(enum pipe_format surf_fmt,
298                           SVGA3dSurfaceFormat surf_svga_fmt,
299                           enum pipe_format view_fmt)
300 {
301    if (surf_fmt == view_fmt || svga_format_is_typeless(surf_svga_fmt))
302       return true;
303 
304    if ((surf_fmt == PIPE_FORMAT_B8G8R8X8_UNORM &&
305         view_fmt == PIPE_FORMAT_B8G8R8A8_UNORM) ||
306        (surf_fmt == PIPE_FORMAT_B8G8R8A8_UNORM &&
307         view_fmt == PIPE_FORMAT_B8G8R8X8_UNORM))
308       return true;
309 
310    return false;
311 }
312 
313 
314 static void
svga_blit(struct pipe_context * pipe,const struct pipe_blit_info * blit_info)315 svga_blit(struct pipe_context *pipe,
316           const struct pipe_blit_info *blit_info)
317 {
318    struct svga_context *svga = svga_context(pipe);
319    struct pipe_blit_info blit = *blit_info;
320    struct pipe_resource *src = blit.src.resource;
321    struct pipe_resource *dst = blit.dst.resource;
322    struct pipe_resource *newSrc = NULL;
323    struct pipe_resource *newDst = NULL;
324    bool can_create_src_view;
325    bool can_create_dst_view;
326 
327    if (!svga_have_vgpu10(svga) &&
328        blit.src.resource->nr_samples > 1 &&
329        blit.dst.resource->nr_samples <= 1 &&
330        !util_format_is_depth_or_stencil(blit.src.resource->format) &&
331        !util_format_is_pure_integer(blit.src.resource->format)) {
332       debug_printf("svga: color resolve unimplemented\n");
333       return;
334    }
335 
336    if (can_blit_via_copy_region_vgpu10(svga, blit_info)) {
337       unsigned src_face, src_z, dst_face, dst_z;
338 
339       adjust_z_layer(blit.src.resource->target, blit.src.box.z,
340                      &src_face, &src_z);
341 
342       adjust_z_layer(blit.dst.resource->target, blit.dst.box.z,
343                      &dst_face, &dst_z);
344 
345       copy_region_vgpu10(svga,
346                          blit.src.resource,
347                          blit.src.box.x, blit.src.box.y, src_z,
348                          blit.src.level, src_face,
349                          blit.dst.resource,
350                          blit.dst.box.x, blit.dst.box.y, dst_z,
351                          blit.dst.level, dst_face,
352                          blit.src.box.width, blit.src.box.height,
353                          blit.src.box.depth);
354       return;
355    }
356 
357    if (util_can_blit_via_copy_region(blit_info, TRUE) ||
358        util_can_blit_via_copy_region(blit_info, FALSE)) {
359       util_resource_copy_region(pipe, blit.dst.resource,
360                                 blit.dst.level,
361                                 blit.dst.box.x, blit.dst.box.y,
362                                 blit.dst.box.z, blit.src.resource,
363                                 blit.src.level, &blit.src.box);
364       return; /* done */
365    }
366 
367    /* Check if we can create shader resource view and
368     * render target view for the quad blitter to work
369     */
370    can_create_src_view =
371       is_view_format_compatible(src->format, svga_texture(src)->key.format,
372                                 blit.src.format);
373 
374    can_create_dst_view =
375       is_view_format_compatible(dst->format, svga_texture(dst)->key.format,
376                                 blit.dst.format);
377 
378    if ((blit.mask & PIPE_MASK_S) ||
379        ((!can_create_dst_view || !can_create_src_view)
380         && !svga_have_vgpu10(svga)) ||
381        !util_blitter_is_blit_supported(svga->blitter, &blit)) {
382       debug_printf("svga: blit unsupported %s -> %s\n",
383                    util_format_short_name(blit.src.resource->format),
384                    util_format_short_name(blit.dst.resource->format));
385       return;
386    }
387 
388    /* XXX turn off occlusion and streamout queries */
389 
390    util_blitter_save_vertex_buffer_slot(svga->blitter, svga->curr.vb);
391    util_blitter_save_vertex_elements(svga->blitter, (void*)svga->curr.velems);
392    util_blitter_save_vertex_shader(svga->blitter, svga->curr.vs);
393    util_blitter_save_geometry_shader(svga->blitter, svga->curr.user_gs);
394    util_blitter_save_so_targets(svga->blitter, svga->num_so_targets,
395                      (struct pipe_stream_output_target**)svga->so_targets);
396    util_blitter_save_rasterizer(svga->blitter, (void*)svga->curr.rast);
397    util_blitter_save_viewport(svga->blitter, &svga->curr.viewport);
398    util_blitter_save_scissor(svga->blitter, &svga->curr.scissor);
399    util_blitter_save_fragment_shader(svga->blitter, svga->curr.fs);
400    util_blitter_save_blend(svga->blitter, (void*)svga->curr.blend);
401    util_blitter_save_depth_stencil_alpha(svga->blitter,
402                                          (void*)svga->curr.depth);
403    util_blitter_save_stencil_ref(svga->blitter, &svga->curr.stencil_ref);
404    util_blitter_save_sample_mask(svga->blitter, svga->curr.sample_mask);
405    util_blitter_save_framebuffer(svga->blitter, &svga->curr.framebuffer);
406    util_blitter_save_fragment_sampler_states(svga->blitter,
407                      svga->curr.num_samplers[PIPE_SHADER_FRAGMENT],
408                      (void**)svga->curr.sampler[PIPE_SHADER_FRAGMENT]);
409    util_blitter_save_fragment_sampler_views(svga->blitter,
410                      svga->curr.num_sampler_views[PIPE_SHADER_FRAGMENT],
411                      svga->curr.sampler_views[PIPE_SHADER_FRAGMENT]);
412    /*util_blitter_save_render_condition(svga->blitter, svga->render_cond_query,
413                                       svga->render_cond_cond, svga->render_cond_mode);*/
414 
415    if (!can_create_src_view) {
416       struct pipe_resource template;
417       unsigned src_face, src_z;
418 
419       /**
420        * If the source blit format is not compatible with the source resource
421        * format, we will not be able to create a shader resource view.
422        * In order to avoid falling back to software blit, we'll create
423        * a new resource in the blit format, and use DXCopyResource to
424        * copy from the original format to the new format. The new
425        * resource will be used for the blit in util_blitter_blit().
426        */
427       template = *src;
428       template.format = blit.src.format;
429       newSrc = svga_texture_create(svga->pipe.screen, &template);
430       if (newSrc == NULL) {
431          debug_printf("svga_blit: fails to create temporary src\n");
432          return;
433       }
434 
435       /* Copy from original resource to the temporary resource */
436       adjust_z_layer(blit.src.resource->target, blit.src.box.z,
437                      &src_face, &src_z);
438 
439       copy_region_vgpu10(svga,
440                          blit.src.resource,
441                          blit.src.box.x, blit.src.box.y, src_z,
442                          blit.src.level, src_face,
443                          newSrc,
444                          blit.src.box.x, blit.src.box.y, src_z,
445                          blit.src.level, src_face,
446                          blit.src.box.width, blit.src.box.height,
447                          blit.src.box.depth);
448 
449       blit.src.resource = newSrc;
450    }
451 
452    if (!can_create_dst_view) {
453       struct pipe_resource template;
454 
455       /**
456        * If the destination blit format is not compatible with the destination
457        * resource format, we will not be able to create a render target view.
458        * In order to avoid falling back to software blit, we'll create
459        * a new resource in the blit format, and use DXPredCopyRegion
460        * after the blit to copy from the blit format back to the resource
461        * format.
462        */
463       template = *dst;
464       template.format = blit.dst.format;
465       newDst = svga_texture_create(svga->pipe.screen, &template);
466       if (newDst == NULL) {
467          debug_printf("svga_blit: fails to create temporary dst\n");
468          return;
469       }
470 
471       blit.dst.resource = newDst;
472    }
473 
474    util_blitter_blit(svga->blitter, &blit);
475 
476    if (blit.dst.resource != dst) {
477       unsigned dst_face, dst_z;
478 
479       adjust_z_layer(blit.dst.resource->target, blit.dst.box.z,
480                      &dst_face, &dst_z);
481 
482       /**
483        * A temporary resource was created for the blit, we need to
484        * copy from the temporary resource back to the original destination.
485        */
486       copy_region_vgpu10(svga,
487                          blit.dst.resource,
488                          blit.dst.box.x, blit.dst.box.y, dst_z,
489                          blit.dst.level, dst_face,
490                          dst,
491                          blit.dst.box.x, blit.dst.box.y, dst_z,
492                          blit.dst.level, dst_face,
493                          blit.dst.box.width, blit.dst.box.height,
494                          blit.dst.box.depth);
495 
496       /* unreference the temporary resource */
497       pipe_resource_reference(&newDst, NULL);
498       blit.dst.resource = dst;
499    }
500 
501    if (blit.src.resource != src) {
502       /* unreference the temporary resource */
503       pipe_resource_reference(&newSrc, NULL);
504       blit.src.resource = src;
505    }
506 }
507 
508 
509 static void
svga_flush_resource(struct pipe_context * pipe,struct pipe_resource * resource)510 svga_flush_resource(struct pipe_context *pipe,
511                     struct pipe_resource *resource)
512 {
513 }
514 
515 
516 void
svga_init_blit_functions(struct svga_context * svga)517 svga_init_blit_functions(struct svga_context *svga)
518 {
519    svga->pipe.resource_copy_region = svga_resource_copy_region;
520    svga->pipe.blit = svga_blit;
521    svga->pipe.flush_resource = svga_flush_resource;
522 }
523