2 * Copyright 2008 Corbin Simpson <MostAwesomeDude@gmail.com>
3 * Copyright 2010 Marek Olšák <maraeo@gmail.com>
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * on the rights to use, copy, modify, merge, publish, distribute, sub
9 * license, and/or sell copies of the Software, and to permit persons to whom
10 * the Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
22 * USE OR OTHER DEALINGS IN THE SOFTWARE. */
24 #include "r300_context.h"
25 #include "r300_transfer.h"
26 #include "r300_texture.h"
27 #include "r300_screen.h"
29 #include "r300_winsys.h"
31 #include "util/u_memory.h"
32 #include "util/u_format.h"
34 struct r300_transfer
{
36 struct pipe_transfer transfer
;
39 struct pipe_context
*ctx
;
41 /* Parameters of get_tex_transfer. */
42 unsigned x
, y
, level
, zslice
, face
;
44 /* Offset from start of buffer. */
47 /* Detiled texture. */
48 struct r300_texture
*detiled_texture
;
50 /* Transfer and format flags. */
51 unsigned buffer_usage
, render_target_usage
;
54 /* Convenience cast wrapper. */
55 static INLINE
struct r300_transfer
*
56 r300_transfer(struct pipe_transfer
* transfer
)
58 return (struct r300_transfer
*)transfer
;
61 /* Copy from a tiled texture to a detiled one. */
62 static void r300_copy_from_tiled_texture(struct pipe_context
*ctx
,
63 struct r300_transfer
*r300transfer
)
65 struct pipe_screen
*screen
= ctx
->screen
;
66 struct pipe_transfer
*transfer
= (struct pipe_transfer
*)r300transfer
;
67 struct pipe_texture
*tex
= transfer
->texture
;
68 struct pipe_surface
*src
, *dst
;
70 src
= screen
->get_tex_surface(screen
, tex
, r300transfer
->face
,
71 r300transfer
->level
, r300transfer
->zslice
,
72 PIPE_BUFFER_USAGE_GPU_READ
|
73 PIPE_BUFFER_USAGE_PIXEL
);
75 dst
= screen
->get_tex_surface(screen
, &r300transfer
->detiled_texture
->tex
,
77 PIPE_BUFFER_USAGE_GPU_WRITE
|
78 PIPE_BUFFER_USAGE_PIXEL
|
79 r300transfer
->buffer_usage
);
81 ctx
->surface_copy(ctx
, dst
, 0, 0, src
, r300transfer
->x
, r300transfer
->y
,
82 transfer
->width
, transfer
->height
);
84 pipe_surface_reference(&src
, NULL
);
85 pipe_surface_reference(&dst
, NULL
);
88 /* Copy a detiled texture to a tiled one. */
89 static void r300_copy_into_tiled_texture(struct pipe_context
*ctx
,
90 struct r300_transfer
*r300transfer
)
92 struct pipe_screen
*screen
= ctx
->screen
;
93 struct pipe_transfer
*transfer
= (struct pipe_transfer
*)r300transfer
;
94 struct pipe_texture
*tex
= transfer
->texture
;
95 struct pipe_surface
*src
, *dst
;
97 src
= screen
->get_tex_surface(screen
, &r300transfer
->detiled_texture
->tex
,
99 PIPE_BUFFER_USAGE_GPU_READ
|
100 PIPE_BUFFER_USAGE_PIXEL
);
102 dst
= screen
->get_tex_surface(screen
, tex
, r300transfer
->face
,
103 r300transfer
->level
, r300transfer
->zslice
,
104 PIPE_BUFFER_USAGE_GPU_WRITE
|
105 PIPE_BUFFER_USAGE_PIXEL
);
107 /* XXX this flush prevents the following DRM error from occuring:
108 * [drm:radeon_cs_ioctl] *ERROR* Failed to parse relocation !
109 * Reproducible with perf/copytex. */
110 ctx
->flush(ctx
, 0, NULL
);
112 ctx
->surface_copy(ctx
, dst
, r300transfer
->x
, r300transfer
->y
, src
, 0, 0,
113 transfer
->width
, transfer
->height
);
115 /* XXX this flush fixes a few piglit tests (e.g. glean/pixelFormats). */
116 ctx
->flush(ctx
, 0, NULL
);
118 pipe_surface_reference(&src
, NULL
);
119 pipe_surface_reference(&dst
, NULL
);
122 static struct pipe_transfer
*
123 r300_get_tex_transfer(struct pipe_context
*ctx
,
124 struct pipe_texture
*texture
,
125 unsigned face
, unsigned level
, unsigned zslice
,
126 enum pipe_transfer_usage usage
, unsigned x
, unsigned y
,
127 unsigned w
, unsigned h
)
129 struct r300_texture
*tex
= r300_texture(texture
);
130 struct r300_screen
*r300screen
= r300_screen(ctx
->screen
);
131 struct r300_transfer
*trans
;
132 struct pipe_texture base
;
134 trans
= CALLOC_STRUCT(r300_transfer
);
136 /* Initialize the transfer object. */
137 pipe_texture_reference(&trans
->transfer
.texture
, texture
);
138 trans
->transfer
.usage
= usage
;
139 trans
->transfer
.width
= w
;
140 trans
->transfer
.height
= h
;
144 trans
->level
= level
;
145 trans
->zslice
= zslice
;
148 /* If the texture is tiled, we must create a temporary detiled texture
149 * for this transfer. */
150 if (tex
->microtile
|| tex
->macrotile
) {
151 trans
->buffer_usage
= pipe_transfer_buffer_flags(&trans
->transfer
);
152 trans
->render_target_usage
=
153 util_format_is_depth_or_stencil(texture
->format
) ?
154 PIPE_TEXTURE_USAGE_DEPTH_STENCIL
:
155 PIPE_TEXTURE_USAGE_RENDER_TARGET
;
157 base
.target
= PIPE_TEXTURE_2D
;
158 base
.format
= texture
->format
;
164 base
.tex_usage
= PIPE_TEXTURE_USAGE_DYNAMIC
|
165 R300_TEXTURE_USAGE_TRANSFER
;
167 /* For texture reading, the temporary (detiled) texture is used as
168 * a render target when blitting from a tiled texture. */
169 if (usage
& PIPE_TRANSFER_READ
) {
170 base
.tex_usage
|= trans
->render_target_usage
;
172 /* For texture writing, the temporary texture is used as a sampler
173 * when blitting into a tiled texture. */
174 if (usage
& PIPE_TRANSFER_WRITE
) {
175 base
.tex_usage
|= PIPE_TEXTURE_USAGE_SAMPLER
;
178 /* Create the temporary texture. */
179 trans
->detiled_texture
= r300_texture(
180 ctx
->screen
->texture_create(ctx
->screen
,
183 assert(!trans
->detiled_texture
->microtile
&&
184 !trans
->detiled_texture
->macrotile
);
187 * Parameters x, y, level, zslice, and face remain zero. */
188 trans
->transfer
.stride
=
189 r300_texture_get_stride(r300screen
, trans
->detiled_texture
, 0);
191 if (usage
& PIPE_TRANSFER_READ
) {
192 /* We cannot map a tiled texture directly because the data is
193 * in a different order, therefore we do detiling using a blit. */
194 r300_copy_from_tiled_texture(ctx
, trans
);
197 trans
->transfer
.x
= x
;
198 trans
->transfer
.y
= y
;
199 trans
->transfer
.stride
=
200 r300_texture_get_stride(r300screen
, tex
, level
);
201 trans
->transfer
.level
= level
;
202 trans
->transfer
.zslice
= zslice
;
203 trans
->transfer
.face
= face
;
204 trans
->offset
= r300_texture_get_offset(tex
, level
, zslice
, face
);
207 return &trans
->transfer
;
210 static void r300_tex_transfer_destroy(struct pipe_context
*ctx
,
211 struct pipe_transfer
*trans
)
213 struct r300_transfer
*r300transfer
= r300_transfer(trans
);
215 if (r300transfer
->detiled_texture
) {
216 if (trans
->usage
& PIPE_TRANSFER_WRITE
) {
217 r300_copy_into_tiled_texture(r300transfer
->ctx
, r300transfer
);
220 pipe_texture_reference(
221 (struct pipe_texture
**)&r300transfer
->detiled_texture
, NULL
);
223 pipe_texture_reference(&trans
->texture
, NULL
);
227 static void* r300_transfer_map(struct pipe_context
*ctx
,
228 struct pipe_transfer
*transfer
)
230 struct r300_winsys_screen
*rws
= (struct r300_winsys_screen
*)ctx
->winsys
;
231 struct r300_transfer
*r300transfer
= r300_transfer(transfer
);
232 struct r300_texture
*tex
= r300_texture(transfer
->texture
);
234 enum pipe_format format
= tex
->tex
.format
;
236 if (r300transfer
->detiled_texture
) {
237 /* The detiled texture is of the same size as the region being mapped
238 * (no offset needed). */
239 return rws
->buffer_map(rws
,
240 r300transfer
->detiled_texture
->buffer
,
241 pipe_transfer_buffer_flags(transfer
));
243 /* Tiling is disabled. */
244 map
= rws
->buffer_map(rws
, tex
->buffer
,
245 pipe_transfer_buffer_flags(transfer
));
251 return map
+ r300_transfer(transfer
)->offset
+
252 transfer
->y
/ util_format_get_blockheight(format
) * transfer
->stride
+
253 transfer
->x
/ util_format_get_blockwidth(format
) * util_format_get_blocksize(format
);
257 static void r300_transfer_unmap(struct pipe_context
*ctx
,
258 struct pipe_transfer
*transfer
)
260 struct r300_winsys_screen
*rws
= (struct r300_winsys_screen
*)ctx
->winsys
;
261 struct r300_transfer
*r300transfer
= r300_transfer(transfer
);
262 struct r300_texture
*tex
= r300_texture(transfer
->texture
);
264 if (r300transfer
->detiled_texture
) {
265 rws
->buffer_unmap(rws
, r300transfer
->detiled_texture
->buffer
);
267 rws
->buffer_unmap(rws
, tex
->buffer
);
272 void r300_init_transfer_functions( struct r300_context
*r300ctx
)
274 struct pipe_context
*ctx
= &r300ctx
->context
;
276 ctx
->get_tex_transfer
= r300_get_tex_transfer
;
277 ctx
->tex_transfer_destroy
= r300_tex_transfer_destroy
;
278 ctx
->transfer_map
= r300_transfer_map
;
279 ctx
->transfer_unmap
= r300_transfer_unmap
;