Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5564 | serge | 1 | /* |
2 | * Copyright 2010 Jerome Glisse |
||
3 | * |
||
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
5 | * copy of this software and associated documentation files (the "Software"), |
||
6 | * to deal in the Software without restriction, including without limitation |
||
7 | * on the rights to use, copy, modify, merge, publish, distribute, sub |
||
8 | * license, and/or sell copies of the Software, and to permit persons to whom |
||
9 | * the Software is furnished to do so, subject to the following conditions: |
||
10 | * |
||
11 | * The above copyright notice and this permission notice (including the next |
||
12 | * paragraph) shall be included in all copies or substantial portions of the |
||
13 | * Software. |
||
14 | * |
||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL |
||
18 | * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, |
||
19 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
||
20 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
||
21 | * USE OR OTHER DEALINGS IN THE SOFTWARE. |
||
22 | * |
||
23 | * Authors: |
||
24 | * Jerome Glisse |
||
25 | * Corbin Simpson |
||
26 | */ |
||
27 | #include "r600_pipe_common.h" |
||
28 | #include "r600_cs.h" |
||
29 | #include "util/u_format.h" |
||
30 | #include "util/u_memory.h" |
||
31 | #include "util/u_pack_color.h" |
||
32 | #include |
||
33 | #include |
||
34 | |||
35 | /* Same as resource_copy_region, except that both upsampling and downsampling are allowed. */ |
||
36 | static void r600_copy_region_with_blit(struct pipe_context *pipe, |
||
37 | struct pipe_resource *dst, |
||
38 | unsigned dst_level, |
||
39 | unsigned dstx, unsigned dsty, unsigned dstz, |
||
40 | struct pipe_resource *src, |
||
41 | unsigned src_level, |
||
42 | const struct pipe_box *src_box) |
||
43 | { |
||
44 | struct pipe_blit_info blit; |
||
45 | |||
46 | memset(&blit, 0, sizeof(blit)); |
||
47 | blit.src.resource = src; |
||
48 | blit.src.format = src->format; |
||
49 | blit.src.level = src_level; |
||
50 | blit.src.box = *src_box; |
||
51 | blit.dst.resource = dst; |
||
52 | blit.dst.format = dst->format; |
||
53 | blit.dst.level = dst_level; |
||
54 | blit.dst.box.x = dstx; |
||
55 | blit.dst.box.y = dsty; |
||
56 | blit.dst.box.z = dstz; |
||
57 | blit.dst.box.width = src_box->width; |
||
58 | blit.dst.box.height = src_box->height; |
||
59 | blit.dst.box.depth = src_box->depth; |
||
60 | blit.mask = util_format_get_mask(src->format) & |
||
61 | util_format_get_mask(dst->format); |
||
62 | blit.filter = PIPE_TEX_FILTER_NEAREST; |
||
63 | |||
64 | if (blit.mask) { |
||
65 | pipe->blit(pipe, &blit); |
||
66 | } |
||
67 | } |
||
68 | |||
69 | /* Copy from a full GPU texture to a transfer's staging one. */ |
||
70 | static void r600_copy_to_staging_texture(struct pipe_context *ctx, struct r600_transfer *rtransfer) |
||
71 | { |
||
72 | struct r600_common_context *rctx = (struct r600_common_context*)ctx; |
||
73 | struct pipe_transfer *transfer = (struct pipe_transfer*)rtransfer; |
||
74 | struct pipe_resource *dst = &rtransfer->staging->b.b; |
||
75 | struct pipe_resource *src = transfer->resource; |
||
76 | |||
77 | if (src->nr_samples > 1) { |
||
78 | r600_copy_region_with_blit(ctx, dst, 0, 0, 0, 0, |
||
79 | src, transfer->level, &transfer->box); |
||
80 | return; |
||
81 | } |
||
82 | |||
83 | rctx->dma_copy(ctx, dst, 0, 0, 0, 0, src, transfer->level, |
||
84 | &transfer->box); |
||
85 | } |
||
86 | |||
87 | /* Copy from a transfer's staging texture to a full GPU one. */ |
||
88 | static void r600_copy_from_staging_texture(struct pipe_context *ctx, struct r600_transfer *rtransfer) |
||
89 | { |
||
90 | struct r600_common_context *rctx = (struct r600_common_context*)ctx; |
||
91 | struct pipe_transfer *transfer = (struct pipe_transfer*)rtransfer; |
||
92 | struct pipe_resource *dst = transfer->resource; |
||
93 | struct pipe_resource *src = &rtransfer->staging->b.b; |
||
94 | struct pipe_box sbox; |
||
95 | |||
96 | u_box_3d(0, 0, 0, transfer->box.width, transfer->box.height, transfer->box.depth, &sbox); |
||
97 | |||
98 | if (dst->nr_samples > 1) { |
||
99 | r600_copy_region_with_blit(ctx, dst, transfer->level, |
||
100 | transfer->box.x, transfer->box.y, transfer->box.z, |
||
101 | src, 0, &sbox); |
||
102 | return; |
||
103 | } |
||
104 | |||
105 | rctx->dma_copy(ctx, dst, transfer->level, |
||
106 | transfer->box.x, transfer->box.y, transfer->box.z, |
||
107 | src, 0, &sbox); |
||
108 | } |
||
109 | |||
110 | static unsigned r600_texture_get_offset(struct r600_texture *rtex, unsigned level, |
||
111 | const struct pipe_box *box) |
||
112 | { |
||
113 | enum pipe_format format = rtex->resource.b.b.format; |
||
114 | |||
115 | return rtex->surface.level[level].offset + |
||
116 | box->z * rtex->surface.level[level].slice_size + |
||
117 | box->y / util_format_get_blockheight(format) * rtex->surface.level[level].pitch_bytes + |
||
118 | box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); |
||
119 | } |
||
120 | |||
121 | static int r600_init_surface(struct r600_common_screen *rscreen, |
||
122 | struct radeon_surf *surface, |
||
123 | const struct pipe_resource *ptex, |
||
124 | unsigned array_mode, |
||
125 | bool is_flushed_depth) |
||
126 | { |
||
127 | const struct util_format_description *desc = |
||
128 | util_format_description(ptex->format); |
||
129 | bool is_depth, is_stencil; |
||
130 | |||
131 | is_depth = util_format_has_depth(desc); |
||
132 | is_stencil = util_format_has_stencil(desc); |
||
133 | |||
134 | surface->npix_x = ptex->width0; |
||
135 | surface->npix_y = ptex->height0; |
||
136 | surface->npix_z = ptex->depth0; |
||
137 | surface->blk_w = util_format_get_blockwidth(ptex->format); |
||
138 | surface->blk_h = util_format_get_blockheight(ptex->format); |
||
139 | surface->blk_d = 1; |
||
140 | surface->array_size = 1; |
||
141 | surface->last_level = ptex->last_level; |
||
142 | |||
143 | if (rscreen->chip_class >= EVERGREEN && !is_flushed_depth && |
||
144 | ptex->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) { |
||
145 | surface->bpe = 4; /* stencil is allocated separately on evergreen */ |
||
146 | } else { |
||
147 | surface->bpe = util_format_get_blocksize(ptex->format); |
||
148 | /* align byte per element on dword */ |
||
149 | if (surface->bpe == 3) { |
||
150 | surface->bpe = 4; |
||
151 | } |
||
152 | } |
||
153 | |||
154 | surface->nsamples = ptex->nr_samples ? ptex->nr_samples : 1; |
||
155 | surface->flags = RADEON_SURF_SET(array_mode, MODE); |
||
156 | |||
157 | switch (ptex->target) { |
||
158 | case PIPE_TEXTURE_1D: |
||
159 | surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_1D, TYPE); |
||
160 | break; |
||
161 | case PIPE_TEXTURE_RECT: |
||
162 | case PIPE_TEXTURE_2D: |
||
163 | surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE); |
||
164 | break; |
||
165 | case PIPE_TEXTURE_3D: |
||
166 | surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_3D, TYPE); |
||
167 | break; |
||
168 | case PIPE_TEXTURE_1D_ARRAY: |
||
169 | surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_1D_ARRAY, TYPE); |
||
170 | surface->array_size = ptex->array_size; |
||
171 | break; |
||
172 | case PIPE_TEXTURE_2D_ARRAY: |
||
173 | case PIPE_TEXTURE_CUBE_ARRAY: /* cube array layout like 2d array */ |
||
174 | surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D_ARRAY, TYPE); |
||
175 | surface->array_size = ptex->array_size; |
||
176 | break; |
||
177 | case PIPE_TEXTURE_CUBE: |
||
178 | surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_CUBEMAP, TYPE); |
||
179 | break; |
||
180 | case PIPE_BUFFER: |
||
181 | default: |
||
182 | return -EINVAL; |
||
183 | } |
||
184 | if (ptex->bind & PIPE_BIND_SCANOUT) { |
||
185 | surface->flags |= RADEON_SURF_SCANOUT; |
||
186 | } |
||
187 | |||
188 | if (!is_flushed_depth && is_depth) { |
||
189 | surface->flags |= RADEON_SURF_ZBUFFER; |
||
190 | |||
191 | if (is_stencil) { |
||
192 | surface->flags |= RADEON_SURF_SBUFFER | |
||
193 | RADEON_SURF_HAS_SBUFFER_MIPTREE; |
||
194 | } |
||
195 | } |
||
196 | if (rscreen->chip_class >= SI) { |
||
197 | surface->flags |= RADEON_SURF_HAS_TILE_MODE_INDEX; |
||
198 | } |
||
199 | return 0; |
||
200 | } |
||
201 | |||
202 | static int r600_setup_surface(struct pipe_screen *screen, |
||
203 | struct r600_texture *rtex, |
||
204 | unsigned pitch_in_bytes_override) |
||
205 | { |
||
206 | struct r600_common_screen *rscreen = (struct r600_common_screen*)screen; |
||
207 | int r; |
||
208 | |||
209 | r = rscreen->ws->surface_init(rscreen->ws, &rtex->surface); |
||
210 | if (r) { |
||
211 | return r; |
||
212 | } |
||
213 | |||
214 | rtex->size = rtex->surface.bo_size; |
||
215 | |||
216 | if (pitch_in_bytes_override && pitch_in_bytes_override != rtex->surface.level[0].pitch_bytes) { |
||
217 | /* old ddx on evergreen over estimate alignment for 1d, only 1 level |
||
218 | * for those |
||
219 | */ |
||
220 | rtex->surface.level[0].nblk_x = pitch_in_bytes_override / rtex->surface.bpe; |
||
221 | rtex->surface.level[0].pitch_bytes = pitch_in_bytes_override; |
||
222 | rtex->surface.level[0].slice_size = pitch_in_bytes_override * rtex->surface.level[0].nblk_y; |
||
223 | if (rtex->surface.flags & RADEON_SURF_SBUFFER) { |
||
224 | rtex->surface.stencil_offset = |
||
225 | rtex->surface.stencil_level[0].offset = rtex->surface.level[0].slice_size; |
||
226 | } |
||
227 | } |
||
228 | return 0; |
||
229 | } |
||
230 | |||
231 | static boolean r600_texture_get_handle(struct pipe_screen* screen, |
||
232 | struct pipe_resource *ptex, |
||
233 | struct winsys_handle *whandle) |
||
234 | { |
||
235 | struct r600_texture *rtex = (struct r600_texture*)ptex; |
||
236 | struct r600_resource *resource = &rtex->resource; |
||
237 | struct radeon_surf *surface = &rtex->surface; |
||
238 | struct r600_common_screen *rscreen = (struct r600_common_screen*)screen; |
||
239 | |||
240 | rscreen->ws->buffer_set_tiling(resource->buf, |
||
241 | NULL, |
||
242 | surface->level[0].mode >= RADEON_SURF_MODE_1D ? |
||
243 | RADEON_LAYOUT_TILED : RADEON_LAYOUT_LINEAR, |
||
244 | surface->level[0].mode >= RADEON_SURF_MODE_2D ? |
||
245 | RADEON_LAYOUT_TILED : RADEON_LAYOUT_LINEAR, |
||
246 | surface->bankw, surface->bankh, |
||
247 | surface->tile_split, |
||
248 | surface->stencil_tile_split, |
||
249 | surface->mtilea, |
||
250 | surface->level[0].pitch_bytes, |
||
251 | (surface->flags & RADEON_SURF_SCANOUT) != 0); |
||
252 | |||
253 | return rscreen->ws->buffer_get_handle(resource->buf, |
||
254 | surface->level[0].pitch_bytes, whandle); |
||
255 | } |
||
256 | |||
257 | static void r600_texture_destroy(struct pipe_screen *screen, |
||
258 | struct pipe_resource *ptex) |
||
259 | { |
||
260 | struct r600_texture *rtex = (struct r600_texture*)ptex; |
||
261 | struct r600_resource *resource = &rtex->resource; |
||
262 | |||
263 | if (rtex->flushed_depth_texture) |
||
264 | pipe_resource_reference((struct pipe_resource **)&rtex->flushed_depth_texture, NULL); |
||
265 | |||
266 | pipe_resource_reference((struct pipe_resource**)&rtex->htile_buffer, NULL); |
||
267 | if (rtex->cmask_buffer != &rtex->resource) { |
||
268 | pipe_resource_reference((struct pipe_resource**)&rtex->cmask_buffer, NULL); |
||
269 | } |
||
270 | pb_reference(&resource->buf, NULL); |
||
271 | FREE(rtex); |
||
272 | } |
||
273 | |||
274 | static const struct u_resource_vtbl r600_texture_vtbl; |
||
275 | |||
276 | /* The number of samples can be specified independently of the texture. */ |
||
277 | void r600_texture_get_fmask_info(struct r600_common_screen *rscreen, |
||
278 | struct r600_texture *rtex, |
||
279 | unsigned nr_samples, |
||
280 | struct r600_fmask_info *out) |
||
281 | { |
||
282 | /* FMASK is allocated like an ordinary texture. */ |
||
283 | struct radeon_surf fmask = rtex->surface; |
||
284 | |||
285 | memset(out, 0, sizeof(*out)); |
||
286 | |||
287 | fmask.bo_alignment = 0; |
||
288 | fmask.bo_size = 0; |
||
289 | fmask.nsamples = 1; |
||
290 | fmask.flags |= RADEON_SURF_FMASK; |
||
291 | |||
292 | /* Force 2D tiling if it wasn't set. This may occur when creating |
||
293 | * FMASK for MSAA resolve on R6xx. On R6xx, the single-sample |
||
294 | * destination buffer must have an FMASK too. */ |
||
295 | fmask.flags = RADEON_SURF_CLR(fmask.flags, MODE); |
||
296 | fmask.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE); |
||
297 | |||
298 | if (rscreen->chip_class >= SI) { |
||
299 | fmask.flags |= RADEON_SURF_HAS_TILE_MODE_INDEX; |
||
300 | } |
||
301 | |||
302 | switch (nr_samples) { |
||
303 | case 2: |
||
304 | case 4: |
||
305 | fmask.bpe = 1; |
||
306 | if (rscreen->chip_class <= CAYMAN) { |
||
307 | fmask.bankh = 4; |
||
308 | } |
||
309 | break; |
||
310 | case 8: |
||
311 | fmask.bpe = 4; |
||
312 | break; |
||
313 | default: |
||
314 | R600_ERR("Invalid sample count for FMASK allocation.\n"); |
||
315 | return; |
||
316 | } |
||
317 | |||
318 | /* Overallocate FMASK on R600-R700 to fix colorbuffer corruption. |
||
319 | * This can be fixed by writing a separate FMASK allocator specifically |
||
320 | * for R600-R700 asics. */ |
||
321 | if (rscreen->chip_class <= R700) { |
||
322 | fmask.bpe *= 2; |
||
323 | } |
||
324 | |||
325 | if (rscreen->ws->surface_init(rscreen->ws, &fmask)) { |
||
326 | R600_ERR("Got error in surface_init while allocating FMASK.\n"); |
||
327 | return; |
||
328 | } |
||
329 | |||
330 | assert(fmask.level[0].mode == RADEON_SURF_MODE_2D); |
||
331 | |||
332 | out->slice_tile_max = (fmask.level[0].nblk_x * fmask.level[0].nblk_y) / 64; |
||
333 | if (out->slice_tile_max) |
||
334 | out->slice_tile_max -= 1; |
||
335 | |||
336 | out->tile_mode_index = fmask.tiling_index[0]; |
||
337 | out->pitch = fmask.level[0].nblk_x; |
||
338 | out->bank_height = fmask.bankh; |
||
339 | out->alignment = MAX2(256, fmask.bo_alignment); |
||
340 | out->size = fmask.bo_size; |
||
341 | } |
||
342 | |||
343 | static void r600_texture_allocate_fmask(struct r600_common_screen *rscreen, |
||
344 | struct r600_texture *rtex) |
||
345 | { |
||
346 | r600_texture_get_fmask_info(rscreen, rtex, |
||
347 | rtex->resource.b.b.nr_samples, &rtex->fmask); |
||
348 | |||
349 | rtex->fmask.offset = align(rtex->size, rtex->fmask.alignment); |
||
350 | rtex->size = rtex->fmask.offset + rtex->fmask.size; |
||
351 | } |
||
352 | |||
353 | void r600_texture_get_cmask_info(struct r600_common_screen *rscreen, |
||
354 | struct r600_texture *rtex, |
||
355 | struct r600_cmask_info *out) |
||
356 | { |
||
357 | unsigned cmask_tile_width = 8; |
||
358 | unsigned cmask_tile_height = 8; |
||
359 | unsigned cmask_tile_elements = cmask_tile_width * cmask_tile_height; |
||
360 | unsigned element_bits = 4; |
||
361 | unsigned cmask_cache_bits = 1024; |
||
362 | unsigned num_pipes = rscreen->tiling_info.num_channels; |
||
363 | unsigned pipe_interleave_bytes = rscreen->tiling_info.group_bytes; |
||
364 | |||
365 | unsigned elements_per_macro_tile = (cmask_cache_bits / element_bits) * num_pipes; |
||
366 | unsigned pixels_per_macro_tile = elements_per_macro_tile * cmask_tile_elements; |
||
367 | unsigned sqrt_pixels_per_macro_tile = sqrt(pixels_per_macro_tile); |
||
368 | unsigned macro_tile_width = util_next_power_of_two(sqrt_pixels_per_macro_tile); |
||
369 | unsigned macro_tile_height = pixels_per_macro_tile / macro_tile_width; |
||
370 | |||
371 | unsigned pitch_elements = align(rtex->surface.npix_x, macro_tile_width); |
||
372 | unsigned height = align(rtex->surface.npix_y, macro_tile_height); |
||
373 | |||
374 | unsigned base_align = num_pipes * pipe_interleave_bytes; |
||
375 | unsigned slice_bytes = |
||
376 | ((pitch_elements * height * element_bits + 7) / 8) / cmask_tile_elements; |
||
377 | |||
378 | assert(macro_tile_width % 128 == 0); |
||
379 | assert(macro_tile_height % 128 == 0); |
||
380 | |||
381 | out->slice_tile_max = ((pitch_elements * height) / (128*128)) - 1; |
||
382 | out->alignment = MAX2(256, base_align); |
||
383 | out->size = (util_max_layer(&rtex->resource.b.b, 0) + 1) * |
||
384 | align(slice_bytes, base_align); |
||
385 | } |
||
386 | |||
387 | static void si_texture_get_cmask_info(struct r600_common_screen *rscreen, |
||
388 | struct r600_texture *rtex, |
||
389 | struct r600_cmask_info *out) |
||
390 | { |
||
391 | unsigned pipe_interleave_bytes = rscreen->tiling_info.group_bytes; |
||
392 | unsigned num_pipes = rscreen->tiling_info.num_channels; |
||
393 | unsigned cl_width, cl_height; |
||
394 | |||
395 | switch (num_pipes) { |
||
396 | case 2: |
||
397 | cl_width = 32; |
||
398 | cl_height = 16; |
||
399 | break; |
||
400 | case 4: |
||
401 | cl_width = 32; |
||
402 | cl_height = 32; |
||
403 | break; |
||
404 | case 8: |
||
405 | cl_width = 64; |
||
406 | cl_height = 32; |
||
407 | break; |
||
408 | case 16: /* Hawaii */ |
||
409 | cl_width = 64; |
||
410 | cl_height = 64; |
||
411 | break; |
||
412 | default: |
||
413 | assert(0); |
||
414 | return; |
||
415 | } |
||
416 | |||
417 | unsigned base_align = num_pipes * pipe_interleave_bytes; |
||
418 | |||
419 | unsigned width = align(rtex->surface.npix_x, cl_width*8); |
||
420 | unsigned height = align(rtex->surface.npix_y, cl_height*8); |
||
421 | unsigned slice_elements = (width * height) / (8*8); |
||
422 | |||
423 | /* Each element of CMASK is a nibble. */ |
||
424 | unsigned slice_bytes = slice_elements / 2; |
||
425 | |||
426 | out->slice_tile_max = (width * height) / (128*128); |
||
427 | if (out->slice_tile_max) |
||
428 | out->slice_tile_max -= 1; |
||
429 | |||
430 | out->alignment = MAX2(256, base_align); |
||
431 | out->size = (util_max_layer(&rtex->resource.b.b, 0) + 1) * |
||
432 | align(slice_bytes, base_align); |
||
433 | } |
||
434 | |||
435 | static void r600_texture_allocate_cmask(struct r600_common_screen *rscreen, |
||
436 | struct r600_texture *rtex) |
||
437 | { |
||
438 | if (rscreen->chip_class >= SI) { |
||
439 | si_texture_get_cmask_info(rscreen, rtex, &rtex->cmask); |
||
440 | } else { |
||
441 | r600_texture_get_cmask_info(rscreen, rtex, &rtex->cmask); |
||
442 | } |
||
443 | |||
444 | rtex->cmask.offset = align(rtex->size, rtex->cmask.alignment); |
||
445 | rtex->size = rtex->cmask.offset + rtex->cmask.size; |
||
446 | |||
447 | if (rscreen->chip_class >= SI) |
||
448 | rtex->cb_color_info |= SI_S_028C70_FAST_CLEAR(1); |
||
449 | else |
||
450 | rtex->cb_color_info |= EG_S_028C70_FAST_CLEAR(1); |
||
451 | } |
||
452 | |||
453 | static void r600_texture_alloc_cmask_separate(struct r600_common_screen *rscreen, |
||
454 | struct r600_texture *rtex) |
||
455 | { |
||
456 | if (rtex->cmask_buffer) |
||
457 | return; |
||
458 | |||
459 | assert(rtex->cmask.size == 0); |
||
460 | |||
461 | if (rscreen->chip_class >= SI) { |
||
462 | si_texture_get_cmask_info(rscreen, rtex, &rtex->cmask); |
||
463 | } else { |
||
464 | r600_texture_get_cmask_info(rscreen, rtex, &rtex->cmask); |
||
465 | } |
||
466 | |||
467 | rtex->cmask_buffer = (struct r600_resource *) |
||
468 | pipe_buffer_create(&rscreen->b, PIPE_BIND_CUSTOM, |
||
469 | PIPE_USAGE_DEFAULT, rtex->cmask.size); |
||
470 | if (rtex->cmask_buffer == NULL) { |
||
471 | rtex->cmask.size = 0; |
||
472 | return; |
||
473 | } |
||
474 | |||
475 | /* update colorbuffer state bits */ |
||
476 | rtex->cmask.base_address_reg = rtex->cmask_buffer->gpu_address >> 8; |
||
477 | |||
478 | if (rscreen->chip_class >= SI) |
||
479 | rtex->cb_color_info |= SI_S_028C70_FAST_CLEAR(1); |
||
480 | else |
||
481 | rtex->cb_color_info |= EG_S_028C70_FAST_CLEAR(1); |
||
482 | } |
||
483 | |||
484 | static unsigned r600_texture_get_htile_size(struct r600_common_screen *rscreen, |
||
485 | struct r600_texture *rtex) |
||
486 | { |
||
487 | unsigned cl_width, cl_height, width, height; |
||
488 | unsigned slice_elements, slice_bytes, pipe_interleave_bytes, base_align; |
||
489 | unsigned num_pipes = rscreen->tiling_info.num_channels; |
||
490 | |||
491 | if (rscreen->chip_class <= EVERGREEN && |
||
492 | rscreen->info.drm_minor < 26) |
||
493 | return 0; |
||
494 | |||
495 | /* HW bug on R6xx. */ |
||
496 | if (rscreen->chip_class == R600 && |
||
497 | (rtex->surface.level[0].npix_x > 7680 || |
||
498 | rtex->surface.level[0].npix_y > 7680)) |
||
499 | return 0; |
||
500 | |||
501 | /* HTILE is broken with 1D tiling on old kernels and CIK. */ |
||
502 | if (rscreen->chip_class >= CIK && |
||
503 | rtex->surface.level[0].mode == RADEON_SURF_MODE_1D && |
||
504 | rscreen->info.drm_minor < 38) |
||
505 | return 0; |
||
506 | |||
507 | switch (num_pipes) { |
||
508 | case 1: |
||
509 | cl_width = 32; |
||
510 | cl_height = 16; |
||
511 | break; |
||
512 | case 2: |
||
513 | cl_width = 32; |
||
514 | cl_height = 32; |
||
515 | break; |
||
516 | case 4: |
||
517 | cl_width = 64; |
||
518 | cl_height = 32; |
||
519 | break; |
||
520 | case 8: |
||
521 | cl_width = 64; |
||
522 | cl_height = 64; |
||
523 | break; |
||
524 | case 16: |
||
525 | cl_width = 128; |
||
526 | cl_height = 64; |
||
527 | break; |
||
528 | default: |
||
529 | assert(0); |
||
530 | return 0; |
||
531 | } |
||
532 | |||
533 | width = align(rtex->surface.npix_x, cl_width * 8); |
||
534 | height = align(rtex->surface.npix_y, cl_height * 8); |
||
535 | |||
536 | slice_elements = (width * height) / (8 * 8); |
||
537 | slice_bytes = slice_elements * 4; |
||
538 | |||
539 | pipe_interleave_bytes = rscreen->tiling_info.group_bytes; |
||
540 | base_align = num_pipes * pipe_interleave_bytes; |
||
541 | |||
542 | return (util_max_layer(&rtex->resource.b.b, 0) + 1) * |
||
543 | align(slice_bytes, base_align); |
||
544 | } |
||
545 | |||
546 | static void r600_texture_allocate_htile(struct r600_common_screen *rscreen, |
||
547 | struct r600_texture *rtex) |
||
548 | { |
||
549 | unsigned htile_size = r600_texture_get_htile_size(rscreen, rtex); |
||
550 | |||
551 | if (!htile_size) |
||
552 | return; |
||
553 | |||
554 | rtex->htile_buffer = (struct r600_resource*) |
||
555 | pipe_buffer_create(&rscreen->b, PIPE_BIND_CUSTOM, |
||
556 | PIPE_USAGE_DEFAULT, htile_size); |
||
557 | if (rtex->htile_buffer == NULL) { |
||
558 | /* this is not a fatal error as we can still keep rendering |
||
559 | * without htile buffer */ |
||
560 | R600_ERR("Failed to create buffer object for htile buffer.\n"); |
||
561 | } else { |
||
562 | r600_screen_clear_buffer(rscreen, &rtex->htile_buffer->b.b, 0, |
||
563 | htile_size, 0, true); |
||
564 | } |
||
565 | } |
||
566 | |||
567 | /* Common processing for r600_texture_create and r600_texture_from_handle */ |
||
568 | static struct r600_texture * |
||
569 | r600_texture_create_object(struct pipe_screen *screen, |
||
570 | const struct pipe_resource *base, |
||
571 | unsigned pitch_in_bytes_override, |
||
572 | struct pb_buffer *buf, |
||
573 | struct radeon_surf *surface) |
||
574 | { |
||
575 | struct r600_texture *rtex; |
||
576 | struct r600_resource *resource; |
||
577 | struct r600_common_screen *rscreen = (struct r600_common_screen*)screen; |
||
578 | |||
579 | rtex = CALLOC_STRUCT(r600_texture); |
||
580 | if (rtex == NULL) |
||
581 | return NULL; |
||
582 | |||
583 | resource = &rtex->resource; |
||
584 | resource->b.b = *base; |
||
585 | resource->b.vtbl = &r600_texture_vtbl; |
||
586 | pipe_reference_init(&resource->b.b.reference, 1); |
||
587 | resource->b.b.screen = screen; |
||
588 | rtex->pitch_override = pitch_in_bytes_override; |
||
589 | |||
590 | /* don't include stencil-only formats which we don't support for rendering */ |
||
591 | rtex->is_depth = util_format_has_depth(util_format_description(rtex->resource.b.b.format)); |
||
592 | |||
593 | rtex->surface = *surface; |
||
594 | if (r600_setup_surface(screen, rtex, pitch_in_bytes_override)) { |
||
595 | FREE(rtex); |
||
596 | return NULL; |
||
597 | } |
||
598 | |||
599 | /* Tiled depth textures utilize the non-displayable tile order. |
||
600 | * This must be done after r600_setup_surface. |
||
601 | * Applies to R600-Cayman. */ |
||
602 | rtex->non_disp_tiling = rtex->is_depth && rtex->surface.level[0].mode >= RADEON_SURF_MODE_1D; |
||
603 | |||
604 | if (rtex->is_depth) { |
||
605 | if (!(base->flags & (R600_RESOURCE_FLAG_TRANSFER | |
||
606 | R600_RESOURCE_FLAG_FLUSHED_DEPTH)) && |
||
607 | !(rscreen->debug_flags & DBG_NO_HYPERZ)) { |
||
608 | |||
609 | r600_texture_allocate_htile(rscreen, rtex); |
||
610 | } |
||
611 | } else { |
||
612 | if (base->nr_samples > 1) { |
||
613 | if (!buf) { |
||
614 | r600_texture_allocate_fmask(rscreen, rtex); |
||
615 | r600_texture_allocate_cmask(rscreen, rtex); |
||
616 | rtex->cmask_buffer = &rtex->resource; |
||
617 | } |
||
618 | if (!rtex->fmask.size || !rtex->cmask.size) { |
||
619 | FREE(rtex); |
||
620 | return NULL; |
||
621 | } |
||
622 | } |
||
623 | } |
||
624 | |||
625 | /* Now create the backing buffer. */ |
||
626 | if (!buf) { |
||
627 | if (!r600_init_resource(rscreen, resource, rtex->size, |
||
628 | rtex->surface.bo_alignment, TRUE)) { |
||
629 | FREE(rtex); |
||
630 | return NULL; |
||
631 | } |
||
632 | } else { |
||
633 | resource->buf = buf; |
||
634 | resource->cs_buf = rscreen->ws->buffer_get_cs_handle(buf); |
||
635 | resource->gpu_address = rscreen->ws->buffer_get_virtual_address(resource->cs_buf); |
||
636 | resource->domains = rscreen->ws->buffer_get_initial_domain(resource->cs_buf); |
||
637 | } |
||
638 | |||
639 | if (rtex->cmask.size) { |
||
640 | /* Initialize the cmask to 0xCC (= compressed state). */ |
||
641 | r600_screen_clear_buffer(rscreen, &rtex->cmask_buffer->b.b, |
||
642 | rtex->cmask.offset, rtex->cmask.size, |
||
643 | 0xCCCCCCCC, true); |
||
644 | } |
||
645 | |||
646 | /* Initialize the CMASK base register value. */ |
||
647 | rtex->cmask.base_address_reg = |
||
648 | (rtex->resource.gpu_address + rtex->cmask.offset) >> 8; |
||
649 | |||
650 | if (rscreen->debug_flags & DBG_VM) { |
||
651 | fprintf(stderr, "VM start=0x%"PRIX64" end=0x%"PRIX64" | Texture %ix%ix%i, %i levels, %i samples, %s\n", |
||
652 | rtex->resource.gpu_address, |
||
653 | rtex->resource.gpu_address + rtex->resource.buf->size, |
||
654 | base->width0, base->height0, util_max_layer(base, 0)+1, base->last_level+1, |
||
655 | base->nr_samples ? base->nr_samples : 1, util_format_short_name(base->format)); |
||
656 | } |
||
657 | |||
658 | if (rscreen->debug_flags & DBG_TEX || |
||
659 | (rtex->resource.b.b.last_level > 0 && rscreen->debug_flags & DBG_TEXMIP)) { |
||
660 | printf("Texture: npix_x=%u, npix_y=%u, npix_z=%u, blk_w=%u, " |
||
661 | "blk_h=%u, blk_d=%u, array_size=%u, last_level=%u, " |
||
662 | "bpe=%u, nsamples=%u, flags=0x%x, %s\n", |
||
663 | rtex->surface.npix_x, rtex->surface.npix_y, |
||
664 | rtex->surface.npix_z, rtex->surface.blk_w, |
||
665 | rtex->surface.blk_h, rtex->surface.blk_d, |
||
666 | rtex->surface.array_size, rtex->surface.last_level, |
||
667 | rtex->surface.bpe, rtex->surface.nsamples, |
||
668 | rtex->surface.flags, util_format_short_name(base->format)); |
||
669 | for (int i = 0; i <= rtex->surface.last_level; i++) { |
||
670 | printf(" L %i: offset=%"PRIu64", slice_size=%"PRIu64", npix_x=%u, " |
||
671 | "npix_y=%u, npix_z=%u, nblk_x=%u, nblk_y=%u, " |
||
672 | "nblk_z=%u, pitch_bytes=%u, mode=%u\n", |
||
673 | i, rtex->surface.level[i].offset, |
||
674 | rtex->surface.level[i].slice_size, |
||
675 | u_minify(rtex->resource.b.b.width0, i), |
||
676 | u_minify(rtex->resource.b.b.height0, i), |
||
677 | u_minify(rtex->resource.b.b.depth0, i), |
||
678 | rtex->surface.level[i].nblk_x, |
||
679 | rtex->surface.level[i].nblk_y, |
||
680 | rtex->surface.level[i].nblk_z, |
||
681 | rtex->surface.level[i].pitch_bytes, |
||
682 | rtex->surface.level[i].mode); |
||
683 | } |
||
684 | if (rtex->surface.flags & RADEON_SURF_SBUFFER) { |
||
685 | for (int i = 0; i <= rtex->surface.last_level; i++) { |
||
686 | printf(" S %i: offset=%"PRIu64", slice_size=%"PRIu64", npix_x=%u, " |
||
687 | "npix_y=%u, npix_z=%u, nblk_x=%u, nblk_y=%u, " |
||
688 | "nblk_z=%u, pitch_bytes=%u, mode=%u\n", |
||
689 | i, rtex->surface.stencil_level[i].offset, |
||
690 | rtex->surface.stencil_level[i].slice_size, |
||
691 | u_minify(rtex->resource.b.b.width0, i), |
||
692 | u_minify(rtex->resource.b.b.height0, i), |
||
693 | u_minify(rtex->resource.b.b.depth0, i), |
||
694 | rtex->surface.stencil_level[i].nblk_x, |
||
695 | rtex->surface.stencil_level[i].nblk_y, |
||
696 | rtex->surface.stencil_level[i].nblk_z, |
||
697 | rtex->surface.stencil_level[i].pitch_bytes, |
||
698 | rtex->surface.stencil_level[i].mode); |
||
699 | } |
||
700 | } |
||
701 | } |
||
702 | return rtex; |
||
703 | } |
||
704 | |||
705 | static unsigned r600_choose_tiling(struct r600_common_screen *rscreen, |
||
706 | const struct pipe_resource *templ) |
||
707 | { |
||
708 | const struct util_format_description *desc = util_format_description(templ->format); |
||
709 | |||
710 | /* MSAA resources must be 2D tiled. */ |
||
711 | if (templ->nr_samples > 1) |
||
712 | return RADEON_SURF_MODE_2D; |
||
713 | |||
714 | /* Transfer resources should be linear. */ |
||
715 | if (templ->flags & R600_RESOURCE_FLAG_TRANSFER) |
||
716 | return RADEON_SURF_MODE_LINEAR_ALIGNED; |
||
717 | |||
718 | /* Handle common candidates for the linear mode. |
||
719 | * Compressed textures must always be tiled. */ |
||
720 | if (!(templ->flags & R600_RESOURCE_FLAG_FORCE_TILING) && |
||
721 | !util_format_is_compressed(templ->format)) { |
||
722 | /* Not everything can be linear, so we cannot enforce it |
||
723 | * for all textures. */ |
||
724 | if ((rscreen->debug_flags & DBG_NO_TILING) && |
||
725 | (!util_format_is_depth_or_stencil(templ->format) || |
||
726 | !(templ->flags & R600_RESOURCE_FLAG_FLUSHED_DEPTH))) |
||
727 | return RADEON_SURF_MODE_LINEAR_ALIGNED; |
||
728 | |||
729 | /* Tiling doesn't work with the 422 (SUBSAMPLED) formats on R600+. */ |
||
730 | if (desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED) |
||
731 | return RADEON_SURF_MODE_LINEAR_ALIGNED; |
||
732 | |||
733 | /* Cursors are linear on SI. |
||
734 | * (XXX double-check, maybe also use RADEON_SURF_SCANOUT) */ |
||
735 | if (rscreen->chip_class >= SI && |
||
736 | (templ->bind & PIPE_BIND_CURSOR)) |
||
737 | return RADEON_SURF_MODE_LINEAR_ALIGNED; |
||
738 | |||
739 | if (templ->bind & PIPE_BIND_LINEAR) |
||
740 | return RADEON_SURF_MODE_LINEAR_ALIGNED; |
||
741 | |||
742 | /* Textures with a very small height are recommended to be linear. */ |
||
743 | if (templ->target == PIPE_TEXTURE_1D || |
||
744 | templ->target == PIPE_TEXTURE_1D_ARRAY || |
||
745 | templ->height0 <= 4) |
||
746 | return RADEON_SURF_MODE_LINEAR_ALIGNED; |
||
747 | |||
748 | /* Textures likely to be mapped often. */ |
||
749 | if (templ->usage == PIPE_USAGE_STAGING || |
||
750 | templ->usage == PIPE_USAGE_STREAM) |
||
751 | return RADEON_SURF_MODE_LINEAR_ALIGNED; |
||
752 | } |
||
753 | |||
754 | /* Make small textures 1D tiled. */ |
||
755 | if (templ->width0 <= 16 || templ->height0 <= 16 || |
||
756 | (rscreen->debug_flags & DBG_NO_2D_TILING)) |
||
757 | return RADEON_SURF_MODE_1D; |
||
758 | |||
759 | /* The allocator will switch to 1D if needed. */ |
||
760 | return RADEON_SURF_MODE_2D; |
||
761 | } |
||
762 | |||
763 | struct pipe_resource *r600_texture_create(struct pipe_screen *screen, |
||
764 | const struct pipe_resource *templ) |
||
765 | { |
||
766 | struct r600_common_screen *rscreen = (struct r600_common_screen*)screen; |
||
767 | struct radeon_surf surface = {0}; |
||
768 | int r; |
||
769 | |||
770 | r = r600_init_surface(rscreen, &surface, templ, |
||
771 | r600_choose_tiling(rscreen, templ), |
||
772 | templ->flags & R600_RESOURCE_FLAG_FLUSHED_DEPTH); |
||
773 | if (r) { |
||
774 | return NULL; |
||
775 | } |
||
776 | r = rscreen->ws->surface_best(rscreen->ws, &surface); |
||
777 | if (r) { |
||
778 | return NULL; |
||
779 | } |
||
780 | return (struct pipe_resource *)r600_texture_create_object(screen, templ, |
||
781 | 0, NULL, &surface); |
||
782 | } |
||
783 | |||
784 | static struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen, |
||
785 | const struct pipe_resource *templ, |
||
786 | struct winsys_handle *whandle) |
||
787 | { |
||
788 | struct r600_common_screen *rscreen = (struct r600_common_screen*)screen; |
||
789 | struct pb_buffer *buf = NULL; |
||
790 | unsigned stride = 0; |
||
791 | unsigned array_mode; |
||
792 | enum radeon_bo_layout micro, macro; |
||
793 | struct radeon_surf surface; |
||
794 | bool scanout; |
||
795 | int r; |
||
796 | |||
797 | /* Support only 2D textures without mipmaps */ |
||
798 | if ((templ->target != PIPE_TEXTURE_2D && templ->target != PIPE_TEXTURE_RECT) || |
||
799 | templ->depth0 != 1 || templ->last_level != 0) |
||
800 | return NULL; |
||
801 | |||
802 | buf = rscreen->ws->buffer_from_handle(rscreen->ws, whandle, &stride); |
||
803 | if (!buf) |
||
804 | return NULL; |
||
805 | |||
806 | rscreen->ws->buffer_get_tiling(buf, µ, ¯o, |
||
807 | &surface.bankw, &surface.bankh, |
||
808 | &surface.tile_split, |
||
809 | &surface.stencil_tile_split, |
||
810 | &surface.mtilea, &scanout); |
||
811 | |||
812 | if (macro == RADEON_LAYOUT_TILED) |
||
813 | array_mode = RADEON_SURF_MODE_2D; |
||
814 | else if (micro == RADEON_LAYOUT_TILED) |
||
815 | array_mode = RADEON_SURF_MODE_1D; |
||
816 | else |
||
817 | array_mode = RADEON_SURF_MODE_LINEAR_ALIGNED; |
||
818 | |||
819 | r = r600_init_surface(rscreen, &surface, templ, array_mode, false); |
||
820 | if (r) { |
||
821 | return NULL; |
||
822 | } |
||
823 | |||
824 | if (scanout) |
||
825 | surface.flags |= RADEON_SURF_SCANOUT; |
||
826 | |||
827 | return (struct pipe_resource *)r600_texture_create_object(screen, templ, |
||
828 | stride, buf, &surface); |
||
829 | } |
||
830 | |||
831 | bool r600_init_flushed_depth_texture(struct pipe_context *ctx, |
||
832 | struct pipe_resource *texture, |
||
833 | struct r600_texture **staging) |
||
834 | { |
||
835 | struct r600_texture *rtex = (struct r600_texture*)texture; |
||
836 | struct pipe_resource resource; |
||
837 | struct r600_texture **flushed_depth_texture = staging ? |
||
838 | staging : &rtex->flushed_depth_texture; |
||
839 | |||
840 | if (!staging && rtex->flushed_depth_texture) |
||
841 | return true; /* it's ready */ |
||
842 | |||
843 | resource.target = texture->target; |
||
844 | resource.format = texture->format; |
||
845 | resource.width0 = texture->width0; |
||
846 | resource.height0 = texture->height0; |
||
847 | resource.depth0 = texture->depth0; |
||
848 | resource.array_size = texture->array_size; |
||
849 | resource.last_level = texture->last_level; |
||
850 | resource.nr_samples = texture->nr_samples; |
||
851 | resource.usage = staging ? PIPE_USAGE_STAGING : PIPE_USAGE_DEFAULT; |
||
852 | resource.bind = texture->bind & ~PIPE_BIND_DEPTH_STENCIL; |
||
853 | resource.flags = texture->flags | R600_RESOURCE_FLAG_FLUSHED_DEPTH; |
||
854 | |||
855 | if (staging) |
||
856 | resource.flags |= R600_RESOURCE_FLAG_TRANSFER; |
||
857 | |||
858 | *flushed_depth_texture = (struct r600_texture *)ctx->screen->resource_create(ctx->screen, &resource); |
||
859 | if (*flushed_depth_texture == NULL) { |
||
860 | R600_ERR("failed to create temporary texture to hold flushed depth\n"); |
||
861 | return false; |
||
862 | } |
||
863 | |||
864 | (*flushed_depth_texture)->is_flushing_texture = TRUE; |
||
865 | (*flushed_depth_texture)->non_disp_tiling = false; |
||
866 | return true; |
||
867 | } |
||
868 | |||
869 | /** |
||
870 | * Initialize the pipe_resource descriptor to be of the same size as the box, |
||
871 | * which is supposed to hold a subregion of the texture "orig" at the given |
||
872 | * mipmap level. |
||
873 | */ |
||
874 | static void r600_init_temp_resource_from_box(struct pipe_resource *res, |
||
875 | struct pipe_resource *orig, |
||
876 | const struct pipe_box *box, |
||
877 | unsigned level, unsigned flags) |
||
878 | { |
||
879 | memset(res, 0, sizeof(*res)); |
||
880 | res->format = orig->format; |
||
881 | res->width0 = box->width; |
||
882 | res->height0 = box->height; |
||
883 | res->depth0 = 1; |
||
884 | res->array_size = 1; |
||
885 | res->usage = flags & R600_RESOURCE_FLAG_TRANSFER ? PIPE_USAGE_STAGING : PIPE_USAGE_DEFAULT; |
||
886 | res->flags = flags; |
||
887 | |||
888 | /* We must set the correct texture target and dimensions for a 3D box. */ |
||
889 | if (box->depth > 1 && util_max_layer(orig, level) > 0) |
||
890 | res->target = orig->target; |
||
891 | else |
||
892 | res->target = PIPE_TEXTURE_2D; |
||
893 | |||
894 | switch (res->target) { |
||
895 | case PIPE_TEXTURE_1D_ARRAY: |
||
896 | case PIPE_TEXTURE_2D_ARRAY: |
||
897 | case PIPE_TEXTURE_CUBE_ARRAY: |
||
898 | res->array_size = box->depth; |
||
899 | break; |
||
900 | case PIPE_TEXTURE_3D: |
||
901 | res->depth0 = box->depth; |
||
902 | break; |
||
903 | default:; |
||
904 | } |
||
905 | } |
||
906 | |||
907 | static void *r600_texture_transfer_map(struct pipe_context *ctx, |
||
908 | struct pipe_resource *texture, |
||
909 | unsigned level, |
||
910 | unsigned usage, |
||
911 | const struct pipe_box *box, |
||
912 | struct pipe_transfer **ptransfer) |
||
913 | { |
||
914 | struct r600_common_context *rctx = (struct r600_common_context*)ctx; |
||
915 | struct r600_texture *rtex = (struct r600_texture*)texture; |
||
916 | struct r600_transfer *trans; |
||
917 | boolean use_staging_texture = FALSE; |
||
918 | struct r600_resource *buf; |
||
919 | unsigned offset = 0; |
||
920 | char *map; |
||
921 | |||
922 | /* We cannot map a tiled texture directly because the data is |
||
923 | * in a different order, therefore we do detiling using a blit. |
||
924 | * |
||
925 | * Also, use a temporary in GTT memory for read transfers, as |
||
926 | * the CPU is much happier reading out of cached system memory |
||
927 | * than uncached VRAM. |
||
928 | */ |
||
929 | if (rtex->surface.level[0].mode >= RADEON_SURF_MODE_1D) { |
||
930 | use_staging_texture = TRUE; |
||
931 | } else if ((usage & PIPE_TRANSFER_READ) && !(usage & PIPE_TRANSFER_MAP_DIRECTLY) && |
||
932 | (rtex->resource.domains == RADEON_DOMAIN_VRAM)) { |
||
933 | /* Untiled buffers in VRAM, which is slow for CPU reads */ |
||
934 | use_staging_texture = TRUE; |
||
935 | } else if (!(usage & PIPE_TRANSFER_READ) && |
||
936 | (r600_rings_is_buffer_referenced(rctx, rtex->resource.cs_buf, RADEON_USAGE_READWRITE) || |
||
937 | rctx->ws->buffer_is_busy(rtex->resource.buf, RADEON_USAGE_READWRITE))) { |
||
938 | /* Use a staging texture for uploads if the underlying BO is busy. */ |
||
939 | use_staging_texture = TRUE; |
||
940 | } |
||
941 | |||
942 | if (texture->flags & R600_RESOURCE_FLAG_TRANSFER) { |
||
943 | use_staging_texture = FALSE; |
||
944 | } |
||
945 | |||
946 | if (use_staging_texture && (usage & PIPE_TRANSFER_MAP_DIRECTLY)) { |
||
947 | return NULL; |
||
948 | } |
||
949 | |||
950 | trans = CALLOC_STRUCT(r600_transfer); |
||
951 | if (trans == NULL) |
||
952 | return NULL; |
||
953 | trans->transfer.resource = texture; |
||
954 | trans->transfer.level = level; |
||
955 | trans->transfer.usage = usage; |
||
956 | trans->transfer.box = *box; |
||
957 | |||
958 | if (rtex->is_depth) { |
||
959 | struct r600_texture *staging_depth; |
||
960 | |||
961 | if (rtex->resource.b.b.nr_samples > 1) { |
||
962 | /* MSAA depth buffers need to be converted to single sample buffers. |
||
963 | * |
||
964 | * Mapping MSAA depth buffers can occur if ReadPixels is called |
||
965 | * with a multisample GLX visual. |
||
966 | * |
||
967 | * First downsample the depth buffer to a temporary texture, |
||
968 | * then decompress the temporary one to staging. |
||
969 | * |
||
970 | * Only the region being mapped is transfered. |
||
971 | */ |
||
972 | struct pipe_resource resource; |
||
973 | |||
974 | r600_init_temp_resource_from_box(&resource, texture, box, level, 0); |
||
975 | |||
976 | if (!r600_init_flushed_depth_texture(ctx, &resource, &staging_depth)) { |
||
977 | R600_ERR("failed to create temporary texture to hold untiled copy\n"); |
||
978 | FREE(trans); |
||
979 | return NULL; |
||
980 | } |
||
981 | |||
982 | if (usage & PIPE_TRANSFER_READ) { |
||
983 | struct pipe_resource *temp = ctx->screen->resource_create(ctx->screen, &resource); |
||
984 | |||
985 | r600_copy_region_with_blit(ctx, temp, 0, 0, 0, 0, texture, level, box); |
||
986 | rctx->blit_decompress_depth(ctx, (struct r600_texture*)temp, staging_depth, |
||
987 | 0, 0, 0, box->depth, 0, 0); |
||
988 | pipe_resource_reference((struct pipe_resource**)&temp, NULL); |
||
989 | } |
||
990 | } |
||
991 | else { |
||
992 | /* XXX: only readback the rectangle which is being mapped? */ |
||
993 | /* XXX: when discard is true, no need to read back from depth texture */ |
||
994 | if (!r600_init_flushed_depth_texture(ctx, texture, &staging_depth)) { |
||
995 | R600_ERR("failed to create temporary texture to hold untiled copy\n"); |
||
996 | FREE(trans); |
||
997 | return NULL; |
||
998 | } |
||
999 | |||
1000 | rctx->blit_decompress_depth(ctx, rtex, staging_depth, |
||
1001 | level, level, |
||
1002 | box->z, box->z + box->depth - 1, |
||
1003 | 0, 0); |
||
1004 | |||
1005 | offset = r600_texture_get_offset(staging_depth, level, box); |
||
1006 | } |
||
1007 | |||
1008 | trans->transfer.stride = staging_depth->surface.level[level].pitch_bytes; |
||
1009 | trans->transfer.layer_stride = staging_depth->surface.level[level].slice_size; |
||
1010 | trans->staging = (struct r600_resource*)staging_depth; |
||
1011 | } else if (use_staging_texture) { |
||
1012 | struct pipe_resource resource; |
||
1013 | struct r600_texture *staging; |
||
1014 | |||
1015 | r600_init_temp_resource_from_box(&resource, texture, box, level, |
||
1016 | R600_RESOURCE_FLAG_TRANSFER); |
||
1017 | resource.usage = (usage & PIPE_TRANSFER_READ) ? |
||
1018 | PIPE_USAGE_STAGING : PIPE_USAGE_STREAM; |
||
1019 | |||
1020 | /* Create the temporary texture. */ |
||
1021 | staging = (struct r600_texture*)ctx->screen->resource_create(ctx->screen, &resource); |
||
1022 | if (staging == NULL) { |
||
1023 | R600_ERR("failed to create temporary texture to hold untiled copy\n"); |
||
1024 | FREE(trans); |
||
1025 | return NULL; |
||
1026 | } |
||
1027 | trans->staging = &staging->resource; |
||
1028 | trans->transfer.stride = staging->surface.level[0].pitch_bytes; |
||
1029 | trans->transfer.layer_stride = staging->surface.level[0].slice_size; |
||
1030 | if (usage & PIPE_TRANSFER_READ) { |
||
1031 | r600_copy_to_staging_texture(ctx, trans); |
||
1032 | } |
||
1033 | } else { |
||
1034 | /* the resource is mapped directly */ |
||
1035 | trans->transfer.stride = rtex->surface.level[level].pitch_bytes; |
||
1036 | trans->transfer.layer_stride = rtex->surface.level[level].slice_size; |
||
1037 | offset = r600_texture_get_offset(rtex, level, box); |
||
1038 | } |
||
1039 | |||
1040 | if (trans->staging) { |
||
1041 | buf = trans->staging; |
||
1042 | if (!rtex->is_depth && !(usage & PIPE_TRANSFER_READ)) |
||
1043 | usage |= PIPE_TRANSFER_UNSYNCHRONIZED; |
||
1044 | } else { |
||
1045 | buf = &rtex->resource; |
||
1046 | } |
||
1047 | |||
1048 | if (!(map = r600_buffer_map_sync_with_rings(rctx, buf, usage))) { |
||
1049 | pipe_resource_reference((struct pipe_resource**)&trans->staging, NULL); |
||
1050 | FREE(trans); |
||
1051 | return NULL; |
||
1052 | } |
||
1053 | |||
1054 | *ptransfer = &trans->transfer; |
||
1055 | return map + offset; |
||
1056 | } |
||
1057 | |||
1058 | static void r600_texture_transfer_unmap(struct pipe_context *ctx, |
||
1059 | struct pipe_transfer* transfer) |
||
1060 | { |
||
1061 | struct r600_transfer *rtransfer = (struct r600_transfer*)transfer; |
||
1062 | struct r600_common_context *rctx = (struct r600_common_context*)ctx; |
||
1063 | struct radeon_winsys_cs_handle *buf; |
||
1064 | struct pipe_resource *texture = transfer->resource; |
||
1065 | struct r600_texture *rtex = (struct r600_texture*)texture; |
||
1066 | |||
1067 | if (rtransfer->staging) { |
||
1068 | buf = rtransfer->staging->cs_buf; |
||
1069 | } else { |
||
1070 | buf = r600_resource(transfer->resource)->cs_buf; |
||
1071 | } |
||
1072 | rctx->ws->buffer_unmap(buf); |
||
1073 | |||
1074 | if ((transfer->usage & PIPE_TRANSFER_WRITE) && rtransfer->staging) { |
||
1075 | if (rtex->is_depth && rtex->resource.b.b.nr_samples <= 1) { |
||
1076 | ctx->resource_copy_region(ctx, texture, transfer->level, |
||
1077 | transfer->box.x, transfer->box.y, transfer->box.z, |
||
1078 | &rtransfer->staging->b.b, transfer->level, |
||
1079 | &transfer->box); |
||
1080 | } else { |
||
1081 | r600_copy_from_staging_texture(ctx, rtransfer); |
||
1082 | } |
||
1083 | } |
||
1084 | |||
1085 | if (rtransfer->staging) |
||
1086 | pipe_resource_reference((struct pipe_resource**)&rtransfer->staging, NULL); |
||
1087 | |||
1088 | FREE(transfer); |
||
1089 | } |
||
1090 | |||
1091 | static const struct u_resource_vtbl r600_texture_vtbl = |
||
1092 | { |
||
1093 | NULL, /* get_handle */ |
||
1094 | r600_texture_destroy, /* resource_destroy */ |
||
1095 | r600_texture_transfer_map, /* transfer_map */ |
||
1096 | NULL, /* transfer_flush_region */ |
||
1097 | r600_texture_transfer_unmap, /* transfer_unmap */ |
||
1098 | NULL /* transfer_inline_write */ |
||
1099 | }; |
||
1100 | |||
1101 | struct pipe_surface *r600_create_surface_custom(struct pipe_context *pipe, |
||
1102 | struct pipe_resource *texture, |
||
1103 | const struct pipe_surface *templ, |
||
1104 | unsigned width, unsigned height) |
||
1105 | { |
||
1106 | struct r600_surface *surface = CALLOC_STRUCT(r600_surface); |
||
1107 | |||
1108 | if (surface == NULL) |
||
1109 | return NULL; |
||
1110 | |||
1111 | assert(templ->u.tex.first_layer <= util_max_layer(texture, templ->u.tex.level)); |
||
1112 | assert(templ->u.tex.last_layer <= util_max_layer(texture, templ->u.tex.level)); |
||
1113 | |||
1114 | pipe_reference_init(&surface->base.reference, 1); |
||
1115 | pipe_resource_reference(&surface->base.texture, texture); |
||
1116 | surface->base.context = pipe; |
||
1117 | surface->base.format = templ->format; |
||
1118 | surface->base.width = width; |
||
1119 | surface->base.height = height; |
||
1120 | surface->base.u = templ->u; |
||
1121 | return &surface->base; |
||
1122 | } |
||
1123 | |||
1124 | static struct pipe_surface *r600_create_surface(struct pipe_context *pipe, |
||
1125 | struct pipe_resource *tex, |
||
1126 | const struct pipe_surface *templ) |
||
1127 | { |
||
1128 | unsigned level = templ->u.tex.level; |
||
1129 | |||
1130 | return r600_create_surface_custom(pipe, tex, templ, |
||
1131 | u_minify(tex->width0, level), |
||
1132 | u_minify(tex->height0, level)); |
||
1133 | } |
||
1134 | |||
1135 | static void r600_surface_destroy(struct pipe_context *pipe, |
||
1136 | struct pipe_surface *surface) |
||
1137 | { |
||
1138 | struct r600_surface *surf = (struct r600_surface*)surface; |
||
1139 | pipe_resource_reference((struct pipe_resource**)&surf->cb_buffer_fmask, NULL); |
||
1140 | pipe_resource_reference((struct pipe_resource**)&surf->cb_buffer_cmask, NULL); |
||
1141 | pipe_resource_reference(&surface->texture, NULL); |
||
1142 | FREE(surface); |
||
1143 | } |
||
1144 | |||
1145 | unsigned r600_translate_colorswap(enum pipe_format format) |
||
1146 | { |
||
1147 | const struct util_format_description *desc = util_format_description(format); |
||
1148 | |||
1149 | #define HAS_SWIZZLE(chan,swz) (desc->swizzle[chan] == UTIL_FORMAT_SWIZZLE_##swz) |
||
1150 | |||
1151 | if (format == PIPE_FORMAT_R11G11B10_FLOAT) /* isn't plain */ |
||
1152 | return V_0280A0_SWAP_STD; |
||
1153 | |||
1154 | if (desc->layout != UTIL_FORMAT_LAYOUT_PLAIN) |
||
1155 | return ~0U; |
||
1156 | |||
1157 | switch (desc->nr_channels) { |
||
1158 | case 1: |
||
1159 | if (HAS_SWIZZLE(0,X)) |
||
1160 | return V_0280A0_SWAP_STD; /* X___ */ |
||
1161 | else if (HAS_SWIZZLE(3,X)) |
||
1162 | return V_0280A0_SWAP_ALT_REV; /* ___X */ |
||
1163 | break; |
||
1164 | case 2: |
||
1165 | if ((HAS_SWIZZLE(0,X) && HAS_SWIZZLE(1,Y)) || |
||
1166 | (HAS_SWIZZLE(0,X) && HAS_SWIZZLE(1,NONE)) || |
||
1167 | (HAS_SWIZZLE(0,NONE) && HAS_SWIZZLE(1,Y))) |
||
1168 | return V_0280A0_SWAP_STD; /* XY__ */ |
||
1169 | else if ((HAS_SWIZZLE(0,Y) && HAS_SWIZZLE(1,X)) || |
||
1170 | (HAS_SWIZZLE(0,Y) && HAS_SWIZZLE(1,NONE)) || |
||
1171 | (HAS_SWIZZLE(0,NONE) && HAS_SWIZZLE(1,X))) |
||
1172 | return V_0280A0_SWAP_STD_REV; /* YX__ */ |
||
1173 | else if (HAS_SWIZZLE(0,X) && HAS_SWIZZLE(3,Y)) |
||
1174 | return V_0280A0_SWAP_ALT; /* X__Y */ |
||
1175 | else if (HAS_SWIZZLE(0,Y) && HAS_SWIZZLE(3,X)) |
||
1176 | return V_0280A0_SWAP_ALT_REV; /* Y__X */ |
||
1177 | break; |
||
1178 | case 3: |
||
1179 | if (HAS_SWIZZLE(0,X)) |
||
1180 | return V_0280A0_SWAP_STD; /* XYZ */ |
||
1181 | else if (HAS_SWIZZLE(0,Z)) |
||
1182 | return V_0280A0_SWAP_STD_REV; /* ZYX */ |
||
1183 | break; |
||
1184 | case 4: |
||
1185 | /* check the middle channels, the 1st and 4th channel can be NONE */ |
||
1186 | if (HAS_SWIZZLE(1,Y) && HAS_SWIZZLE(2,Z)) |
||
1187 | return V_0280A0_SWAP_STD; /* XYZW */ |
||
1188 | else if (HAS_SWIZZLE(1,Z) && HAS_SWIZZLE(2,Y)) |
||
1189 | return V_0280A0_SWAP_STD_REV; /* WZYX */ |
||
1190 | else if (HAS_SWIZZLE(1,Y) && HAS_SWIZZLE(2,X)) |
||
1191 | return V_0280A0_SWAP_ALT; /* ZYXW */ |
||
1192 | else if (HAS_SWIZZLE(1,X) && HAS_SWIZZLE(2,Y)) |
||
1193 | return V_0280A0_SWAP_ALT_REV; /* WXYZ */ |
||
1194 | break; |
||
1195 | } |
||
1196 | return ~0U; |
||
1197 | } |
||
1198 | |||
1199 | static void evergreen_set_clear_color(struct r600_texture *rtex, |
||
1200 | enum pipe_format surface_format, |
||
1201 | const union pipe_color_union *color) |
||
1202 | { |
||
1203 | union util_color uc; |
||
1204 | |||
1205 | memset(&uc, 0, sizeof(uc)); |
||
1206 | |||
1207 | if (util_format_is_pure_uint(surface_format)) { |
||
1208 | util_format_write_4ui(surface_format, color->ui, 0, &uc, 0, 0, 0, 1, 1); |
||
1209 | } else if (util_format_is_pure_sint(surface_format)) { |
||
1210 | util_format_write_4i(surface_format, color->i, 0, &uc, 0, 0, 0, 1, 1); |
||
1211 | } else { |
||
1212 | util_pack_color(color->f, surface_format, &uc); |
||
1213 | } |
||
1214 | |||
1215 | memcpy(rtex->color_clear_value, &uc, 2 * sizeof(uint32_t)); |
||
1216 | } |
||
1217 | |||
1218 | void evergreen_do_fast_color_clear(struct r600_common_context *rctx, |
||
1219 | struct pipe_framebuffer_state *fb, |
||
1220 | struct r600_atom *fb_state, |
||
1221 | unsigned *buffers, |
||
1222 | const union pipe_color_union *color) |
||
1223 | { |
||
1224 | int i; |
||
1225 | |||
1226 | if (rctx->current_render_cond) |
||
1227 | return; |
||
1228 | |||
1229 | for (i = 0; i < fb->nr_cbufs; i++) { |
||
1230 | struct r600_texture *tex; |
||
1231 | unsigned clear_bit = PIPE_CLEAR_COLOR0 << i; |
||
1232 | |||
1233 | if (!fb->cbufs[i]) |
||
1234 | continue; |
||
1235 | |||
1236 | /* if this colorbuffer is not being cleared */ |
||
1237 | if (!(*buffers & clear_bit)) |
||
1238 | continue; |
||
1239 | |||
1240 | tex = (struct r600_texture *)fb->cbufs[i]->texture; |
||
1241 | |||
1242 | /* 128-bit formats are unusupported */ |
||
1243 | if (util_format_get_blocksizebits(fb->cbufs[i]->format) > 64) { |
||
1244 | continue; |
||
1245 | } |
||
1246 | |||
1247 | /* the clear is allowed if all layers are bound */ |
||
1248 | if (fb->cbufs[i]->u.tex.first_layer != 0 || |
||
1249 | fb->cbufs[i]->u.tex.last_layer != util_max_layer(&tex->resource.b.b, 0)) { |
||
1250 | continue; |
||
1251 | } |
||
1252 | |||
1253 | /* cannot clear mipmapped textures */ |
||
1254 | if (fb->cbufs[i]->texture->last_level != 0) { |
||
1255 | continue; |
||
1256 | } |
||
1257 | |||
1258 | /* only supported on tiled surfaces */ |
||
1259 | if (tex->surface.level[0].mode < RADEON_SURF_MODE_1D) { |
||
1260 | continue; |
||
1261 | } |
||
1262 | |||
1263 | /* fast color clear with 1D tiling doesn't work on old kernels and CIK */ |
||
1264 | if (tex->surface.level[0].mode == RADEON_SURF_MODE_1D && |
||
1265 | rctx->chip_class >= CIK && rctx->screen->info.drm_minor < 38) { |
||
1266 | continue; |
||
1267 | } |
||
1268 | |||
1269 | /* ensure CMASK is enabled */ |
||
1270 | r600_texture_alloc_cmask_separate(rctx->screen, tex); |
||
1271 | if (tex->cmask.size == 0) { |
||
1272 | continue; |
||
1273 | } |
||
1274 | |||
1275 | /* Do the fast clear. */ |
||
1276 | evergreen_set_clear_color(tex, fb->cbufs[i]->format, color); |
||
1277 | rctx->clear_buffer(&rctx->b, &tex->cmask_buffer->b.b, |
||
1278 | tex->cmask.offset, tex->cmask.size, 0, true); |
||
1279 | |||
1280 | tex->dirty_level_mask |= 1 << fb->cbufs[i]->u.tex.level; |
||
1281 | fb_state->dirty = true; |
||
1282 | *buffers &= ~clear_bit; |
||
1283 | } |
||
1284 | } |
||
1285 | |||
1286 | void r600_init_screen_texture_functions(struct r600_common_screen *rscreen) |
||
1287 | { |
||
1288 | rscreen->b.resource_from_handle = r600_texture_from_handle; |
||
1289 | rscreen->b.resource_get_handle = r600_texture_get_handle; |
||
1290 | } |
||
1291 | |||
1292 | void r600_init_context_texture_functions(struct r600_common_context *rctx) |
||
1293 | { |
||
1294 | rctx->b.create_surface = r600_create_surface; |
||
1295 | rctx->b.surface_destroy = r600_surface_destroy; |
||
1296 | }><>>>><>>=>=>=>=>=>=>=>=>>>=>=>=> |