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