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_rect.h"
36 #include "util/u_blitter.h"
38 #include "nouveau/nouveau_winsys.h"
39 #include "nouveau/nouveau_util.h"
40 #include "nouveau/nouveau_screen.h"
41 #include "nvfx_context.h"
42 #include "nvfx_screen.h"
43 #include "nvfx_resource.h"
46 #include <nouveau/nouveau_bo.h>
49 nvfx_region_set_format(struct nv04_region
* rgn
, enum pipe_format format
)
51 unsigned bits
= util_format_get_blocksizebits(format
);
64 assert(util_is_pot(bits
));
65 int shift
= log2i(bits
) - 3;
70 rgn
->x
= util_format_get_nblocksx(format
, rgn
->x
) << shift
;
71 rgn
->y
= util_format_get_nblocksy(format
, rgn
->y
);
76 nvfx_region_fixup_swizzled(struct nv04_region
* rgn
, unsigned zslice
, unsigned width
, unsigned height
, unsigned depth
)
78 // TODO: move this code to surface creation?
79 if((depth
<= 1) && (height
<= 1 || width
<= 2))
80 rgn
->pitch
= width
<< rgn
->bpps
;
81 else if(depth
> 1 && height
<= 2 && width
<= 2)
83 rgn
->pitch
= width
<< rgn
->bpps
;
84 rgn
->offset
+= (zslice
* width
* height
) << rgn
->bpps
;
97 nvfx_region_init_for_surface(struct nv04_region
* rgn
, struct nvfx_surface
* surf
, unsigned x
, unsigned y
)
99 rgn
->bo
= ((struct nvfx_resource
*)surf
->base
.texture
)->bo
;
100 rgn
->offset
= surf
->base
.offset
;
101 rgn
->pitch
= surf
->pitch
;
106 nvfx_region_set_format(rgn
, surf
->base
.format
);
107 if(!(surf
->base
.texture
->flags
& NVFX_RESOURCE_FLAG_LINEAR
))
108 nvfx_region_fixup_swizzled(rgn
, surf
->base
.zslice
, surf
->base
.width
, surf
->base
.height
, u_minify(surf
->base
.texture
->depth0
, surf
->base
.level
));
112 nvfx_region_init_for_subresource(struct nv04_region
* rgn
, struct pipe_resource
* pt
, struct pipe_subresource sub
, unsigned x
, unsigned y
, unsigned z
)
114 rgn
->bo
= ((struct nvfx_resource
*)pt
)->bo
;
115 rgn
->offset
= nvfx_subresource_offset(pt
, sub
.face
, sub
.level
, z
);
116 rgn
->pitch
= nvfx_subresource_pitch(pt
, sub
.level
);
121 nvfx_region_set_format(rgn
, pt
->format
);
122 if(!(pt
->flags
& NVFX_RESOURCE_FLAG_LINEAR
))
123 nvfx_region_fixup_swizzled(rgn
, z
, u_minify(pt
->width0
, sub
.level
), u_minify(pt
->height0
, sub
.level
), u_minify(pt
->depth0
, sub
.level
));
126 // TODO: actually test this for all formats, it's probably wrong for some...
129 nvfx_surface_format(enum pipe_format format
)
131 switch(util_format_get_blocksize(format
)) {
133 return NV04_CONTEXT_SURFACES_2D_FORMAT_Y8
;
135 //return NV04_CONTEXT_SURFACES_2D_FORMAT_Y16;
136 return NV04_CONTEXT_SURFACES_2D_FORMAT_R5G6B5
;
138 //if(format == PIPE_FORMAT_B8G8R8X8_UNORM || format == PIPE_FORMAT_B8G8R8A8_UNORM)
139 return NV04_CONTEXT_SURFACES_2D_FORMAT_A8R8G8B8
;
141 // return NV04_CONTEXT_SURFACES_2D_FORMAT_Y32;
148 nv04_scaled_image_format(enum pipe_format format
)
150 switch(util_format_get_blocksize(format
)) {
152 return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_Y8
;
154 //if(format == PIPE_FORMAT_B5G5R5A1_UNORM)
155 // return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_A1R5G5B5;
157 return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_R5G6B5
;
159 if(format
== PIPE_FORMAT_B8G8R8X8_UNORM
)
160 return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_X8R8G8B8
;
162 return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_A8R8G8B8
;
168 static struct blitter_context
*
169 nvfx_get_blitter(struct pipe_context
* pipe
, int copy
)
171 struct nvfx_context
* nvfx
= nvfx_context(pipe
);
173 struct blitter_context
* blitter
= nvfx
->blitter
;
175 nvfx
->blitter
= blitter
= util_blitter_create(pipe
);
177 util_blitter_save_blend(blitter
, nvfx
->blend
);
178 util_blitter_save_depth_stencil_alpha(blitter
, nvfx
->zsa
);
179 util_blitter_save_stencil_ref(blitter
, &nvfx
->stencil_ref
);
180 util_blitter_save_rasterizer(blitter
, nvfx
->rasterizer
);
181 util_blitter_save_fragment_shader(blitter
, nvfx
->fragprog
);
182 util_blitter_save_vertex_shader(blitter
, nvfx
->vertprog
);
183 util_blitter_save_viewport(blitter
, &nvfx
->viewport
);
184 util_blitter_save_framebuffer(blitter
, &nvfx
->framebuffer
);
185 util_blitter_save_clip(blitter
, &nvfx
->clip
);
186 util_blitter_save_vertex_elements(blitter
, nvfx
->vtxelt
);
187 util_blitter_save_vertex_buffers(blitter
, nvfx
->vtxbuf_nr
, nvfx
->vtxbuf
);
191 util_blitter_save_fragment_sampler_states(blitter
, nvfx
->nr_samplers
, (void**)nvfx
->tex_sampler
);
192 util_blitter_save_fragment_sampler_views(blitter
, nvfx
->nr_textures
, nvfx
->fragment_sampler_views
);
199 nvfx_region_clone(struct nv04_2d_context
* ctx
, struct nv04_region
* rgn
, unsigned w
, unsigned h
, boolean for_read
)
201 unsigned begin
= nv04_region_begin(rgn
, w
, h
);
202 unsigned end
= nv04_region_end(rgn
, w
, h
);
203 unsigned size
= end
- begin
;
204 struct nouveau_bo
* bo
= 0;
205 nouveau_bo_new(rgn
->bo
->device
, NOUVEAU_BO_MAP
| NOUVEAU_BO_GART
, 256, size
, &bo
);
207 if(for_read
|| (size
> ((w
* h
) << rgn
->bpps
)))
208 nv04_memcpy(ctx
, bo
, 0, rgn
->bo
, rgn
->offset
+ begin
, size
);
211 rgn
->offset
= -begin
;
216 nvfx_resource_copy_region(struct pipe_context
*pipe
,
217 struct pipe_resource
*dstr
, struct pipe_subresource subdst
,
218 unsigned dstx
, unsigned dsty
, unsigned dstz
,
219 struct pipe_resource
*srcr
, struct pipe_subresource subsrc
,
220 unsigned srcx
, unsigned srcy
, unsigned srcz
,
221 unsigned w
, unsigned h
)
223 struct nv04_2d_context
*ctx
= nvfx_screen(pipe
->screen
)->eng2d
;
224 struct nv04_region dst
, src
;
229 static int copy_threshold
= -1;
230 if(copy_threshold
< 0)
232 copy_threshold
= debug_get_num_option("NOUVEAU_COPY_THRESHOLD", 0);
233 if(copy_threshold
< 0)
237 int dst_to_gpu
= dstr
->usage
!= PIPE_USAGE_DYNAMIC
&& dstr
->usage
!= PIPE_USAGE_STAGING
;
238 int src_on_gpu
= nvfx_resource_on_gpu(srcr
);
240 nvfx_region_init_for_subresource(&dst
, dstr
, subdst
, dstx
, dsty
, dstz
);
241 nvfx_region_init_for_subresource(&src
, srcr
, subsrc
, srcx
, srcy
, srcz
);
242 w
= util_format_get_stride(dstr
->format
, w
) >> dst
.bpps
;
243 h
= util_format_get_nblocksy(dstr
->format
, h
);
246 boolean small
= (w
* h
<= copy_threshold
);
247 if((!dst_to_gpu
|| !src_on_gpu
) && small
)
248 ret
= -1; /* use the CPU */
250 ret
= nv04_region_copy_2d(ctx
, &dst
, &src
, w
, h
,
251 dstr
->target
== PIPE_BUFFER
? -1 : nvfx_surface_format(dstr
->format
),
252 dstr
->target
== PIPE_BUFFER
? -1 : nv04_scaled_image_format(dstr
->format
),
253 dst_to_gpu
, src_on_gpu
);
256 else if(ret
> 0 && dstr
->bind
& PIPE_BIND_RENDER_TARGET
&& srcr
->bind
& PIPE_BIND_SAMPLER_VIEW
)
258 struct blitter_context
* blitter
= nvfx_get_blitter(pipe
, 1);
259 util_blitter_copy_region(blitter
, dstr
, subdst
, dstx
, dsty
, dstz
, srcr
, subsrc
, srcx
, srcy
, srcz
, w
, h
, TRUE
);
263 struct nv04_region dstt
= dst
;
264 struct nv04_region srct
= src
;
265 unsigned dstbegin
= 0;
270 nvfx_region_clone(ctx
, &srct
, w
, h
, TRUE
);
273 dstbegin
= nvfx_region_clone(ctx
, &dstt
, w
, h
, FALSE
);
276 nv04_region_copy_cpu(&dstt
, &srct
, w
, h
);
278 if(srct
.bo
!= src
.bo
)
279 nouveau_screen_bo_release(pipe
->screen
, srct
.bo
);
281 if(dstt
.bo
!= dst
.bo
)
283 nv04_memcpy(ctx
, dst
.bo
, dst
.offset
+ dstbegin
, dstt
.bo
, 0, dstt
.bo
->size
);
284 nouveau_screen_bo_release(pipe
->screen
, dstt
.bo
);
290 nvfx_surface_fill(struct pipe_context
* pipe
, struct pipe_surface
*dsts
,
291 unsigned dx
, unsigned dy
, unsigned w
, unsigned h
, unsigned value
)
293 struct nv04_2d_context
*ctx
= nvfx_screen(pipe
->screen
)->eng2d
;
294 struct nv04_region dst
;
295 /* Always try to use the GPU right now, if possible
296 * If the user wanted the surface data on the CPU, he would have cleared with memset */
298 // we don't care about interior pixel order since we set all them to the same value
299 nvfx_region_init_for_surface(&dst
, (struct nvfx_surface
*)dsts
, dx
, dy
);
300 w
= util_format_get_stride(dsts
->format
, w
) >> dst
.bpps
;
301 h
= util_format_get_nblocksy(dsts
->format
, h
);
303 int ret
= nv04_region_fill_2d(ctx
, &dst
, w
, h
, value
);
304 if(ret
> 0 && dsts
->texture
->bind
& PIPE_BIND_RENDER_TARGET
)
308 struct nv04_region dstt
= dst
;
309 unsigned dstbegin
= 0;
311 if(nvfx_resource_on_gpu(dsts
->texture
))
312 dstbegin
= nvfx_region_clone(ctx
, &dstt
, w
, h
, FALSE
);
314 nv04_region_fill_cpu(&dstt
, w
, h
, value
);
316 if(dstt
.bo
!= dst
.bo
)
318 nv04_memcpy(ctx
, dst
.bo
, dst
.offset
+ dstbegin
, dstt
.bo
, 0, dstt
.bo
->size
);
319 nouveau_screen_bo_release(pipe
->screen
, dstt
.bo
);
328 nvfx_screen_surface_takedown(struct pipe_screen
*pscreen
)
330 nv04_2d_context_takedown(nvfx_screen(pscreen
)->eng2d
);
331 nvfx_screen(pscreen
)->eng2d
= 0;
335 nvfx_screen_surface_init(struct pipe_screen
*pscreen
)
337 struct nv04_2d_context
* ctx
= nv04_2d_context_init(nouveau_screen(pscreen
)->channel
);
340 nvfx_screen(pscreen
)->eng2d
= ctx
;
345 nvfx_clear_render_target(struct pipe_context
*pipe
,
346 struct pipe_surface
*dst
,
348 unsigned dstx
, unsigned dsty
,
349 unsigned width
, unsigned height
)
352 util_pack_color(rgba
, dst
->format
, &uc
);
354 if(util_format_get_blocksizebits(dst
->format
) > 32
355 || nvfx_surface_fill(pipe
, dst
, dstx
, dsty
, width
, height
, uc
.ui
))
357 // TODO: probably should use hardware clear here instead if possible
358 struct blitter_context
* blitter
= nvfx_get_blitter(pipe
, 0);
359 util_blitter_clear_render_target(blitter
, dst
, rgba
, dstx
, dsty
, width
, height
);
364 nvfx_clear_depth_stencil(struct pipe_context
*pipe
,
365 struct pipe_surface
*dst
,
366 unsigned clear_flags
,
369 unsigned dstx
, unsigned dsty
,
370 unsigned width
, unsigned height
)
372 if(util_format_get_blocksizebits(dst
->format
) > 32
373 || nvfx_surface_fill(pipe
, dst
, dstx
, dsty
, width
, height
, util_pack_z_stencil(dst
->format
, depth
, stencil
)))
375 // TODO: probably should use hardware clear here instead if possible
376 struct blitter_context
* blitter
= nvfx_get_blitter(pipe
, 0);
377 util_blitter_clear_depth_stencil(blitter
, dst
, clear_flags
, depth
, stencil
, dstx
, dsty
, width
, height
);
383 nvfx_init_surface_functions(struct nvfx_context
*nvfx
)
385 nvfx
->pipe
.resource_copy_region
= nvfx_resource_copy_region
;
386 nvfx
->pipe
.clear_render_target
= nvfx_clear_render_target
;
387 nvfx
->pipe
.clear_depth_stencil
= nvfx_clear_depth_stencil
;