2 /**************************************************************************
4 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 **************************************************************************/
29 #include "pipe/p_context.h"
30 #include "pipe/p_format.h"
31 #include "util/u_format.h"
32 #include "util/u_math.h"
33 #include "util/u_memory.h"
34 #include "util/u_pack_color.h"
35 #include "util/u_blitter.h"
36 #include "util/u_surface.h"
38 #include "nouveau/nouveau_winsys.h"
39 #include "nouveau/nouveau_screen.h"
40 #include "nvfx_context.h"
41 #include "nvfx_screen.h"
42 #include "nvfx_resource.h"
45 #include <nouveau/nouveau_bo.h>
48 nvfx_region_set_format(struct nv04_region
* rgn
, enum pipe_format format
)
50 unsigned bits
= util_format_get_blocksizebits(format
);
61 if(format
== PIPE_FORMAT_B5G5R5X1_UNORM
)
66 if(format
== PIPE_FORMAT_R8G8B8X8_UNORM
|| format
== PIPE_FORMAT_B8G8R8X8_UNORM
)
80 rgn
->x
= util_format_get_nblocksx(format
, rgn
->x
) << shift
;
81 rgn
->y
= util_format_get_nblocksy(format
, rgn
->y
);
87 nvfx_region_init_for_surface(struct nv04_region
* rgn
, struct nvfx_surface
* surf
, unsigned x
, unsigned y
, boolean for_write
)
95 rgn
->bo
= surf
->temp
->base
.bo
;
97 rgn
->pitch
= surf
->temp
->linear_pitch
;
100 util_dirty_surface_set_dirty(nvfx_surface_get_dirty_surfaces(&surf
->base
.base
), &surf
->base
);
102 rgn
->bo
= ((struct nvfx_resource
*)surf
->base
.base
.texture
)->bo
;
103 rgn
->offset
= surf
->offset
;
105 if(surf
->base
.base
.texture
->flags
& NVFX_RESOURCE_FLAG_LINEAR
)
106 rgn
->pitch
= surf
->pitch
;
110 rgn
->z
= surf
->base
.base
.u
.tex
.first_layer
;
111 rgn
->w
= surf
->base
.base
.width
;
112 rgn
->h
= surf
->base
.base
.height
;
113 rgn
->d
= u_minify(surf
->base
.base
.texture
->depth0
, surf
->base
.base
.u
.tex
.level
);
117 nvfx_region_set_format(rgn
, surf
->base
.base
.format
);
119 nv04_region_try_to_linearize(rgn
);
123 nvfx_region_init_for_subresource(struct nv04_region
* rgn
, struct pipe_resource
* pt
, unsigned level
, unsigned x
, unsigned y
, unsigned z
, boolean for_write
)
125 if(pt
->target
!= PIPE_BUFFER
)
127 struct nvfx_surface
* ns
= (struct nvfx_surface
*)util_surfaces_peek(&((struct nvfx_miptree
*)pt
)->surfaces
, pt
, level
, z
);
128 if(ns
&& util_dirty_surface_is_dirty(&ns
->base
))
130 nvfx_region_init_for_surface(rgn
, ns
, x
, y
, for_write
);
135 rgn
->bo
= ((struct nvfx_resource
*)pt
)->bo
;
136 rgn
->offset
= nvfx_subresource_offset(pt
, z
, level
, z
);
140 if(pt
->flags
& NVFX_RESOURCE_FLAG_LINEAR
)
142 rgn
->pitch
= nvfx_subresource_pitch(pt
, level
);
149 rgn
->w
= u_minify(pt
->width0
, level
);
150 rgn
->h
= u_minify(pt
->height0
, level
);
151 rgn
->d
= u_minify(pt
->depth0
, level
);
154 nvfx_region_set_format(rgn
, pt
->format
);
156 nv04_region_try_to_linearize(rgn
);
159 // don't save index buffer because blitter doesn't setit
160 static struct blitter_context
*
161 nvfx_get_blitter(struct pipe_context
* pipe
, int copy
)
163 struct nvfx_context
* nvfx
= nvfx_context(pipe
);
164 struct blitter_context
** pblitter
;
165 struct blitter_context
* blitter
;
167 assert(nvfx
->blitters_in_use
< Elements(nvfx
->blitter
));
169 if(nvfx
->query
&& !nvfx
->blitters_in_use
)
171 struct nouveau_channel
* chan
= nvfx
->screen
->base
.channel
;
172 struct nouveau_grobj
*eng3d
= nvfx
->screen
->eng3d
;
173 BEGIN_RING(chan
, eng3d
, NV30_3D_QUERY_ENABLE
, 1);
177 pblitter
= &nvfx
->blitter
[nvfx
->blitters_in_use
++];
179 *pblitter
= util_blitter_create(pipe
);
182 util_blitter_save_blend(blitter
, nvfx
->blend
);
183 util_blitter_save_depth_stencil_alpha(blitter
, nvfx
->zsa
);
184 util_blitter_save_stencil_ref(blitter
, &nvfx
->stencil_ref
);
185 util_blitter_save_rasterizer(blitter
, nvfx
->rasterizer
);
186 util_blitter_save_fragment_shader(blitter
, nvfx
->fragprog
);
187 util_blitter_save_vertex_shader(blitter
, nvfx
->vertprog
);
188 util_blitter_save_viewport(blitter
, &nvfx
->viewport
);
189 util_blitter_save_framebuffer(blitter
, &nvfx
->framebuffer
);
190 util_blitter_save_clip(blitter
, &nvfx
->clip
);
191 util_blitter_save_vertex_elements(blitter
, nvfx
->vtxelt
);
192 util_blitter_save_vertex_buffers(blitter
, nvfx
->vtxbuf_nr
, nvfx
->vtxbuf
);
196 util_blitter_save_fragment_sampler_states(blitter
, nvfx
->nr_samplers
, (void**)nvfx
->tex_sampler
);
197 util_blitter_save_fragment_sampler_views(blitter
, nvfx
->nr_textures
, nvfx
->fragment_sampler_views
);
204 nvfx_put_blitter(struct pipe_context
* pipe
, struct blitter_context
* blitter
)
206 struct nvfx_context
* nvfx
= nvfx_context(pipe
);
207 --nvfx
->blitters_in_use
;
208 assert(nvfx
->blitters_in_use
>= 0);
210 if(nvfx
->query
&& !nvfx
->blitters_in_use
)
212 struct nouveau_channel
* chan
= nvfx
->screen
->base
.channel
;
213 struct nouveau_grobj
*eng3d
= nvfx
->screen
->eng3d
;
214 BEGIN_RING(chan
, eng3d
, NV30_3D_QUERY_ENABLE
, 1);
220 nvfx_region_clone(struct nv04_2d_context
* ctx
, struct nv04_region
* rgn
, unsigned w
, unsigned h
, boolean for_read
)
222 unsigned begin
= nv04_region_begin(rgn
, w
, h
);
223 unsigned end
= nv04_region_end(rgn
, w
, h
);
224 unsigned size
= end
- begin
;
225 struct nouveau_bo
* bo
= 0;
226 nouveau_bo_new(rgn
->bo
->device
, NOUVEAU_BO_MAP
| NOUVEAU_BO_GART
, 256, size
, &bo
);
228 if(for_read
|| (size
> ((w
* h
) << rgn
->bpps
)))
229 nv04_memcpy(ctx
, bo
, 0, rgn
->bo
, rgn
->offset
+ begin
, size
);
232 rgn
->offset
= -begin
;
237 nvfx_resource_copy_region(struct pipe_context
*pipe
,
238 struct pipe_resource
*dstr
, unsigned dst_level
,
239 unsigned dstx
, unsigned dsty
, unsigned dstz
,
240 struct pipe_resource
*srcr
, unsigned src_level
,
241 const struct pipe_box
*src_box
)
243 static int copy_threshold
= -1;
244 struct nv04_2d_context
*ctx
= nvfx_screen(pipe
->screen
)->eng2d
;
245 struct nv04_region dst
, src
;
250 unsigned w
= src_box
->width
;
251 unsigned h
= src_box
->height
;
256 /* Fallback for buffers. */
257 if (dstr
->target
== PIPE_BUFFER
&& srcr
->target
== PIPE_BUFFER
) {
258 util_resource_copy_region(pipe
, dstr
, dst_level
, dstx
, dsty
, dstz
,
259 srcr
, src_level
, src_box
);
263 if(copy_threshold
< 0)
264 copy_threshold
= debug_get_num_option("NOUVEAU_COPY_THRESHOLD", 4);
266 dst_to_gpu
= dstr
->usage
!= PIPE_USAGE_DYNAMIC
&& dstr
->usage
!= PIPE_USAGE_STAGING
;
267 src_on_gpu
= nvfx_resource_on_gpu(srcr
);
269 nvfx_region_init_for_subresource(&dst
, dstr
, dst_level
, dstx
, dsty
, dstz
, TRUE
);
270 nvfx_region_init_for_subresource(&src
, srcr
, src_level
, src_box
->x
, src_box
->y
, src_box
->z
, FALSE
);
271 w
= util_format_get_stride(dstr
->format
, w
) >> dst
.bpps
;
272 h
= util_format_get_nblocksy(dstr
->format
, h
);
274 small
= (w
* h
<= copy_threshold
);
275 if((!dst_to_gpu
|| !src_on_gpu
) && small
)
276 ret
= -1; /* use the CPU */
278 ret
= nv04_region_copy_2d(ctx
, &dst
, &src
, w
, h
, dst_to_gpu
, src_on_gpu
);
282 && dstr
->bind
& (PIPE_BIND_RENDER_TARGET
| PIPE_BIND_DEPTH_STENCIL
)
283 && srcr
->bind
& PIPE_BIND_SAMPLER_VIEW
)
285 /* this currently works because we hack the bind flags on resource creation to be
286 * the maximum set that the resource type actually supports
288 * TODO: perhaps support reinterpreting the formats
290 struct blitter_context
* blitter
= nvfx_get_blitter(pipe
, 1);
291 util_blitter_copy_region(blitter
, dstr
, dst_level
, dstx
, dsty
, dstz
, srcr
, src_level
, src_box
, TRUE
);
292 nvfx_put_blitter(pipe
, blitter
);
296 struct nv04_region dstt
= dst
;
297 struct nv04_region srct
= src
;
298 unsigned dstbegin
= 0;
303 nvfx_region_clone(ctx
, &srct
, w
, h
, TRUE
);
306 dstbegin
= nvfx_region_clone(ctx
, &dstt
, w
, h
, FALSE
);
309 nv04_region_copy_cpu(&dstt
, &srct
, w
, h
);
311 if(srct
.bo
!= src
.bo
)
312 nouveau_screen_bo_release(pipe
->screen
, srct
.bo
);
314 if(dstt
.bo
!= dst
.bo
)
316 nv04_memcpy(ctx
, dst
.bo
, dst
.offset
+ dstbegin
, dstt
.bo
, 0, dstt
.bo
->size
);
317 nouveau_screen_bo_release(pipe
->screen
, dstt
.bo
);
323 nvfx_surface_fill(struct pipe_context
* pipe
, struct pipe_surface
*dsts
,
324 unsigned dx
, unsigned dy
, unsigned w
, unsigned h
, unsigned value
)
326 struct nv04_2d_context
*ctx
= nvfx_screen(pipe
->screen
)->eng2d
;
327 struct nv04_region dst
;
329 /* Always try to use the GPU right now, if possible
330 * If the user wanted the surface data on the CPU, he would have cleared with memset (hopefully) */
332 // we don't care about interior pixel order since we set all them to the same value
333 nvfx_region_init_for_surface(&dst
, (struct nvfx_surface
*)dsts
, dx
, dy
, TRUE
);
335 w
= util_format_get_stride(dsts
->format
, w
) >> dst
.bpps
;
336 h
= util_format_get_nblocksy(dsts
->format
, h
);
338 ret
= nv04_region_fill_2d(ctx
, &dst
, w
, h
, value
);
339 if(ret
> 0 && dsts
->texture
->bind
& PIPE_BIND_RENDER_TARGET
)
343 struct nv04_region dstt
= dst
;
344 unsigned dstbegin
= 0;
346 if(nvfx_resource_on_gpu(dsts
->texture
))
347 dstbegin
= nvfx_region_clone(ctx
, &dstt
, w
, h
, FALSE
);
349 nv04_region_fill_cpu(&dstt
, w
, h
, value
);
351 if(dstt
.bo
!= dst
.bo
)
353 nv04_memcpy(ctx
, dst
.bo
, dst
.offset
+ dstbegin
, dstt
.bo
, 0, dstt
.bo
->size
);
354 nouveau_screen_bo_release(pipe
->screen
, dstt
.bo
);
363 nvfx_screen_surface_takedown(struct pipe_screen
*pscreen
)
365 nv04_2d_context_takedown(nvfx_screen(pscreen
)->eng2d
);
366 nvfx_screen(pscreen
)->eng2d
= 0;
370 nvfx_screen_surface_init(struct pipe_screen
*pscreen
)
372 struct nv04_2d_context
* ctx
= nv04_2d_context_init(nouveau_screen(pscreen
)->channel
);
375 nvfx_screen(pscreen
)->eng2d
= ctx
;
380 nvfx_surface_copy_temp(struct pipe_context
* pipe
, struct pipe_surface
* surf
, int to_temp
)
382 struct nvfx_surface
* ns
= (struct nvfx_surface
*)surf
;
384 struct nvfx_context
* nvfx
= nvfx_context(pipe
);
385 struct nvfx_miptree
* temp
;
386 unsigned use_vertex_buffers
;
387 boolean use_index_buffer
;
388 unsigned base_vertex
;
390 /* temporarily detach the temp, so it isn't used in place of the actual resource */
394 // TODO: we really should do this validation before setting these variable in draw calls
395 use_vertex_buffers
= nvfx
->use_vertex_buffers
;
396 use_index_buffer
= nvfx
->use_index_buffer
;
397 base_vertex
= nvfx
->base_vertex
;
400 assert(surf
->u
.tex
.first_layer
== surf
->u
.tex
.last_layer
);
401 box
.width
= surf
->width
;
402 box
.height
= surf
->height
;
406 box
.z
= surf
->u
.tex
.first_layer
;
407 nvfx_resource_copy_region(pipe
, &temp
->base
.base
, 0, 0, 0, 0, surf
->texture
, surf
->u
.tex
.level
, &box
);
411 nvfx_resource_copy_region(pipe
, surf
->texture
, surf
->u
.tex
.level
, 0, 0, surf
->u
.tex
.first_layer
, &temp
->base
.base
, 0, &box
);
414 /* If this triggers, it probably means we attempted to use the blitter
415 * but failed due to non-renderability of the target.
416 * Obviously, this would lead to infinite recursion if supported. */
421 nvfx
->use_vertex_buffers
= use_vertex_buffers
;
422 nvfx
->use_index_buffer
= use_index_buffer
;
423 nvfx
->base_vertex
= base_vertex
;
425 nvfx
->dirty
|= NVFX_NEW_ARRAYS
;
426 nvfx
->draw_dirty
|= NVFX_NEW_ARRAYS
;
430 nvfx_surface_create_temp(struct pipe_context
* pipe
, struct pipe_surface
* surf
)
432 struct nvfx_surface
* ns
= (struct nvfx_surface
*)surf
;
433 struct pipe_resource
template;
434 memset(&template, 0, sizeof(struct pipe_resource
));
435 template.target
= PIPE_TEXTURE_2D
;
436 template.format
= surf
->format
;
437 template.width0
= surf
->width
;
438 template.height0
= surf
->height
;
440 template.nr_samples
= surf
->texture
->nr_samples
;
441 template.flags
= NVFX_RESOURCE_FLAG_LINEAR
;
443 assert(!ns
->temp
&& !util_dirty_surface_is_dirty(&ns
->base
));
445 ns
->temp
= (struct nvfx_miptree
*)nvfx_miptree_create(pipe
->screen
, &template);
446 nvfx_surface_copy_temp(pipe
, surf
, 1);
450 nvfx_surface_flush(struct pipe_context
* pipe
, struct pipe_surface
* surf
)
452 struct nvfx_context
* nvfx
= (struct nvfx_context
*)pipe
;
453 struct nvfx_surface
* ns
= (struct nvfx_surface
*)surf
;
454 boolean bound
= FALSE
;
456 nvfx_surface_copy_temp(pipe
, surf
, 0);
458 util_dirty_surface_set_clean(nvfx_surface_get_dirty_surfaces(surf
), &ns
->base
);
460 if(nvfx
->framebuffer
.zsbuf
== surf
)
464 for(unsigned i
= 0; i
< nvfx
->framebuffer
.nr_cbufs
; ++i
)
466 if(nvfx
->framebuffer
.cbufs
[i
] == surf
)
475 pipe_resource_reference((struct pipe_resource
**)&ns
->temp
, 0);
479 nvfx_clear_render_target(struct pipe_context
*pipe
,
480 struct pipe_surface
*dst
,
482 unsigned dstx
, unsigned dsty
,
483 unsigned width
, unsigned height
)
486 util_pack_color(rgba
, dst
->format
, &uc
);
488 if(util_format_get_blocksizebits(dst
->format
) > 32
489 || nvfx_surface_fill(pipe
, dst
, dstx
, dsty
, width
, height
, uc
.ui
))
491 // TODO: probably should use hardware clear here instead if possible
492 struct blitter_context
* blitter
= nvfx_get_blitter(pipe
, 0);
493 util_blitter_clear_render_target(blitter
, dst
, rgba
, dstx
, dsty
, width
, height
);
494 nvfx_put_blitter(pipe
, blitter
);
499 nvfx_clear_depth_stencil(struct pipe_context
*pipe
,
500 struct pipe_surface
*dst
,
501 unsigned clear_flags
,
504 unsigned dstx
, unsigned dsty
,
505 unsigned width
, unsigned height
)
507 if(util_format_get_blocksizebits(dst
->format
) > 32
508 || nvfx_surface_fill(pipe
, dst
, dstx
, dsty
, width
, height
, util_pack_z_stencil(dst
->format
, depth
, stencil
)))
510 // TODO: probably should use hardware clear here instead if possible
511 struct blitter_context
* blitter
= nvfx_get_blitter(pipe
, 0);
512 util_blitter_clear_depth_stencil(blitter
, dst
, clear_flags
, depth
, stencil
, dstx
, dsty
, width
, height
);
513 nvfx_put_blitter(pipe
, blitter
);
519 nvfx_init_surface_functions(struct nvfx_context
*nvfx
)
521 nvfx
->pipe
.resource_copy_region
= nvfx_resource_copy_region
;
522 nvfx
->pipe
.clear_render_target
= nvfx_clear_render_target
;
523 nvfx
->pipe
.clear_depth_stencil
= nvfx_clear_depth_stencil
;