xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/r300/r300_transfer.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright 2008 Corbin Simpson <[email protected]>
3  * Copyright 2010 Marek Olšák <[email protected]>
4  * SPDX-License-Identifier: MIT
5  */
6 
7 #include "r300_transfer.h"
8 #include "r300_texture_desc.h"
9 #include "r300_screen_buffer.h"
10 
11 #include "util/u_memory.h"
12 #include "util/format/u_format.h"
13 #include "util/box.h"
14 
15 struct r300_transfer {
16     /* Parent class */
17     struct pipe_transfer transfer;
18 
19     /* Linear texture. */
20     struct r300_resource *linear_texture;
21 };
22 
23 /* Convenience cast wrapper. */
24 static inline struct r300_transfer*
r300_transfer(struct pipe_transfer * transfer)25 r300_transfer(struct pipe_transfer* transfer)
26 {
27     return (struct r300_transfer*)transfer;
28 }
29 
30 /* Copy from a tiled texture to a detiled one. */
r300_copy_from_tiled_texture(struct pipe_context * ctx,struct r300_transfer * r300transfer)31 static void r300_copy_from_tiled_texture(struct pipe_context *ctx,
32                                          struct r300_transfer *r300transfer)
33 {
34     struct pipe_transfer *transfer = (struct pipe_transfer*)r300transfer;
35     struct pipe_resource *src = transfer->resource;
36     struct pipe_resource *dst = &r300transfer->linear_texture->b;
37 
38     if (src->nr_samples <= 1) {
39         ctx->resource_copy_region(ctx, dst, 0, 0, 0, 0,
40                                   src, transfer->level, &transfer->box);
41     } else {
42         /* Resolve the resource. */
43         struct pipe_blit_info blit;
44 
45         memset(&blit, 0, sizeof(blit));
46         blit.src.resource = src;
47         blit.src.format = src->format;
48         blit.src.level = transfer->level;
49         blit.src.box = transfer->box;
50         blit.dst.resource = dst;
51         blit.dst.format = dst->format;
52         blit.dst.box.width = transfer->box.width;
53         blit.dst.box.height = transfer->box.height;
54         blit.dst.box.depth = transfer->box.depth;
55         blit.mask = PIPE_MASK_RGBA;
56         blit.filter = PIPE_TEX_FILTER_NEAREST;
57 
58         ctx->blit(ctx, &blit);
59     }
60 }
61 
62 /* Copy a detiled texture to a tiled one. */
r300_copy_into_tiled_texture(struct pipe_context * ctx,struct r300_transfer * r300transfer)63 static void r300_copy_into_tiled_texture(struct pipe_context *ctx,
64                                          struct r300_transfer *r300transfer)
65 {
66     struct pipe_transfer *transfer = (struct pipe_transfer*)r300transfer;
67     struct pipe_resource *tex = transfer->resource;
68     struct pipe_box src_box;
69 
70     u_box_3d(0, 0, 0,
71              transfer->box.width, transfer->box.height, transfer->box.depth,
72              &src_box);
73 
74     ctx->resource_copy_region(ctx, tex, transfer->level,
75                               transfer->box.x, transfer->box.y, transfer->box.z,
76                               &r300transfer->linear_texture->b, 0, &src_box);
77 
78     /* XXX remove this. */
79     r300_flush(ctx, 0, NULL);
80 }
81 
82 void *
r300_texture_transfer_map(struct pipe_context * ctx,struct pipe_resource * texture,unsigned level,unsigned usage,const struct pipe_box * box,struct pipe_transfer ** transfer)83 r300_texture_transfer_map(struct pipe_context *ctx,
84                           struct pipe_resource *texture,
85                           unsigned level,
86                           unsigned usage,
87                           const struct pipe_box *box,
88                           struct pipe_transfer **transfer)
89 {
90     struct r300_context *r300 = r300_context(ctx);
91     struct r300_resource *tex = r300_resource(texture);
92     struct r300_transfer *trans;
93     bool referenced_cs, referenced_hw;
94     enum pipe_format format = tex->b.format;
95     char *map;
96 
97     referenced_cs =
98         r300->rws->cs_is_buffer_referenced(&r300->cs, tex->buf, RADEON_USAGE_READWRITE);
99     if (referenced_cs) {
100         referenced_hw = true;
101     } else {
102         referenced_hw =
103             !r300->rws->buffer_wait(r300->rws, tex->buf, 0, RADEON_USAGE_READWRITE);
104     }
105 
106     trans = CALLOC_STRUCT(r300_transfer);
107     if (trans) {
108         /* Initialize the transfer object. */
109         trans->transfer.resource = texture;
110         trans->transfer.level = level;
111         trans->transfer.usage = usage;
112         trans->transfer.box = *box;
113 
114         /* If the texture is tiled, we must create a temporary detiled texture
115          * for this transfer.
116          * Also make write transfers pipelined. */
117         if (tex->tex.microtile || tex->tex.macrotile[level] ||
118             (referenced_hw && !(usage & PIPE_MAP_READ) &&
119              r300_is_blit_supported(texture->format))) {
120             struct pipe_resource base;
121 
122             if (r300->blitter->running) {
123                 fprintf(stderr, "r300: ERROR: Blitter recursion in texture_get_transfer.\n");
124                 os_break();
125             }
126 
127             memset(&base, 0, sizeof(base));
128             base.target = PIPE_TEXTURE_2D;
129             base.format = texture->format;
130             base.width0 = box->width;
131             base.height0 = box->height;
132             base.depth0 = 1;
133             base.array_size = 1;
134             base.usage = PIPE_USAGE_STAGING;
135             base.flags = R300_RESOURCE_FLAG_TRANSFER;
136 
137             /* We must set the correct texture target and dimensions if needed for a 3D transfer. */
138             if (box->depth > 1 && util_max_layer(texture, level) > 0) {
139                 base.target = texture->target;
140 
141                 if (base.target == PIPE_TEXTURE_3D) {
142                     base.depth0 = util_next_power_of_two(box->depth);
143                 }
144             }
145 
146             /* Create the temporary texture. */
147             trans->linear_texture = r300_resource(
148                ctx->screen->resource_create(ctx->screen,
149                                             &base));
150 
151             if (!trans->linear_texture) {
152                 /* Oh crap, the thing can't create the texture.
153                  * Let's flush and try again. */
154                 r300_flush(ctx, 0, NULL);
155 
156                 trans->linear_texture = r300_resource(
157                    ctx->screen->resource_create(ctx->screen,
158                                                 &base));
159 
160                 if (!trans->linear_texture) {
161                     fprintf(stderr,
162                             "r300: Failed to create a transfer object.\n");
163                     FREE(trans);
164                     return NULL;
165                 }
166             }
167 
168             assert(!trans->linear_texture->tex.microtile &&
169                    !trans->linear_texture->tex.macrotile[0]);
170 
171             /* Set the stride. */
172             trans->transfer.stride =
173                     trans->linear_texture->tex.stride_in_bytes[0];
174             trans->transfer.layer_stride =
175                     trans->linear_texture->tex.layer_size_in_bytes[0];
176 
177             if (usage & PIPE_MAP_READ) {
178                 /* We cannot map a tiled texture directly because the data is
179                  * in a different order, therefore we do detiling using a blit. */
180                 r300_copy_from_tiled_texture(ctx, trans);
181 
182                 /* Always referenced in the blit. */
183                 r300_flush(ctx, 0, NULL);
184             }
185         } else {
186             /* Unpipelined transfer. */
187             trans->transfer.stride = tex->tex.stride_in_bytes[level];
188             trans->transfer.layer_stride = tex->tex.layer_size_in_bytes[level];
189             trans->transfer.offset = r300_texture_get_offset(tex, level, box->z);
190 
191             if (referenced_cs &&
192                 !(usage & PIPE_MAP_UNSYNCHRONIZED)) {
193                 r300_flush(ctx, 0, NULL);
194             }
195         }
196     }
197 
198     if (trans->linear_texture) {
199         /* The detiled texture is of the same size as the region being mapped
200          * (no offset needed). */
201         map = r300->rws->buffer_map(r300->rws, trans->linear_texture->buf,
202                                     &r300->cs, usage);
203         if (!map) {
204             pipe_resource_reference(
205                 (struct pipe_resource**)&trans->linear_texture, NULL);
206             FREE(trans);
207             return NULL;
208         }
209 	*transfer = &trans->transfer;
210         return map;
211     } else {
212         /* Tiling is disabled. */
213         map = r300->rws->buffer_map(r300->rws, tex->buf, &r300->cs, usage);
214         if (!map) {
215             FREE(trans);
216             return NULL;
217         }
218 
219 	*transfer = &trans->transfer;
220         return map + trans->transfer.offset +
221             box->y / util_format_get_blockheight(format) * trans->transfer.stride +
222             box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
223     }
224 }
225 
r300_texture_transfer_unmap(struct pipe_context * ctx,struct pipe_transfer * transfer)226 void r300_texture_transfer_unmap(struct pipe_context *ctx,
227 				 struct pipe_transfer *transfer)
228 {
229     struct r300_transfer *trans = r300_transfer(transfer);
230 
231     if (trans->linear_texture) {
232         if (transfer->usage & PIPE_MAP_WRITE) {
233             r300_copy_into_tiled_texture(ctx, trans);
234         }
235 
236         pipe_resource_reference(
237             (struct pipe_resource**)&trans->linear_texture, NULL);
238     }
239     FREE(transfer);
240 }
241