1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2017 Red Hat 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21bf215546Sopenharmony_ci * SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci#include "pipe/p_screen.h" 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci#include "util/u_box.h" 27bf215546Sopenharmony_ci#include "util/format/u_format.h" 28bf215546Sopenharmony_ci#include "util/format/u_format_rgtc.h" 29bf215546Sopenharmony_ci#include "util/format/u_format_zs.h" 30bf215546Sopenharmony_ci#include "util/u_inlines.h" 31bf215546Sopenharmony_ci#include "util/u_transfer_helper.h" 32bf215546Sopenharmony_ci 33bf215546Sopenharmony_ci 34bf215546Sopenharmony_cistruct u_transfer_helper { 35bf215546Sopenharmony_ci const struct u_transfer_vtbl *vtbl; 36bf215546Sopenharmony_ci bool separate_z32s8; /**< separate z32 and s8 */ 37bf215546Sopenharmony_ci bool separate_stencil; /**< separate stencil for all formats */ 38bf215546Sopenharmony_ci bool fake_rgtc; 39bf215546Sopenharmony_ci bool msaa_map; 40bf215546Sopenharmony_ci bool z24_in_z32f; /* the z24 values are stored in a z32 - translate them. */ 41bf215546Sopenharmony_ci}; 42bf215546Sopenharmony_ci 43bf215546Sopenharmony_cistatic inline bool need_interleave_path(struct u_transfer_helper *helper, 44bf215546Sopenharmony_ci enum pipe_format format) 45bf215546Sopenharmony_ci{ 46bf215546Sopenharmony_ci if (helper->separate_stencil && util_format_is_depth_and_stencil(format)) 47bf215546Sopenharmony_ci return true; 48bf215546Sopenharmony_ci if (helper->separate_z32s8 && format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) 49bf215546Sopenharmony_ci return true; 50bf215546Sopenharmony_ci /* this isn't interleaving, but still needs conversions on that path. */ 51bf215546Sopenharmony_ci if (helper->z24_in_z32f && format == PIPE_FORMAT_Z24X8_UNORM) 52bf215546Sopenharmony_ci return true; 53bf215546Sopenharmony_ci return false; 54bf215546Sopenharmony_ci} 55bf215546Sopenharmony_ci 56bf215546Sopenharmony_cistatic inline bool handle_transfer(struct pipe_resource *prsc) 57bf215546Sopenharmony_ci{ 58bf215546Sopenharmony_ci struct u_transfer_helper *helper = prsc->screen->transfer_helper; 59bf215546Sopenharmony_ci 60bf215546Sopenharmony_ci if (helper->vtbl->get_internal_format) { 61bf215546Sopenharmony_ci enum pipe_format internal_format = 62bf215546Sopenharmony_ci helper->vtbl->get_internal_format(prsc); 63bf215546Sopenharmony_ci if (internal_format != prsc->format) 64bf215546Sopenharmony_ci return true; 65bf215546Sopenharmony_ci } 66bf215546Sopenharmony_ci 67bf215546Sopenharmony_ci if (helper->msaa_map && (prsc->nr_samples > 1)) 68bf215546Sopenharmony_ci return true; 69bf215546Sopenharmony_ci 70bf215546Sopenharmony_ci return false; 71bf215546Sopenharmony_ci} 72bf215546Sopenharmony_ci 73bf215546Sopenharmony_ci/* The pipe_transfer ptr could either be the driver's, or u_transfer, 74bf215546Sopenharmony_ci * depending on whether we are intervening or not. Check handle_transfer() 75bf215546Sopenharmony_ci * before dereferencing. 76bf215546Sopenharmony_ci */ 77bf215546Sopenharmony_cistruct u_transfer { 78bf215546Sopenharmony_ci struct pipe_transfer base; 79bf215546Sopenharmony_ci /* Note that in case of MSAA resolve for transfer plus z32s8 or fake rgtc 80bf215546Sopenharmony_ci * we end up with stacked u_transfer's. The MSAA resolve case doesn't call 81bf215546Sopenharmony_ci * helper->vtbl fxns directly, but calls back to pctx->transfer_map()/etc 82bf215546Sopenharmony_ci * so the format related handling can work in conjunction with MSAA resolve. 83bf215546Sopenharmony_ci */ 84bf215546Sopenharmony_ci struct pipe_transfer *trans; /* driver's transfer */ 85bf215546Sopenharmony_ci struct pipe_transfer *trans2; /* 2nd transfer for s8 stencil buffer in z32s8 */ 86bf215546Sopenharmony_ci void *ptr, *ptr2; /* ptr to trans, and trans2 */ 87bf215546Sopenharmony_ci void *staging; /* staging buffer */ 88bf215546Sopenharmony_ci struct pipe_resource *ss; /* staging resource for MSAA resolves */ 89bf215546Sopenharmony_ci}; 90bf215546Sopenharmony_ci 91bf215546Sopenharmony_cistatic inline struct u_transfer * 92bf215546Sopenharmony_ciu_transfer(struct pipe_transfer *ptrans) 93bf215546Sopenharmony_ci{ 94bf215546Sopenharmony_ci assert(handle_transfer(ptrans->resource)); 95bf215546Sopenharmony_ci return (struct u_transfer *)ptrans; 96bf215546Sopenharmony_ci} 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_cistruct pipe_resource * 99bf215546Sopenharmony_ciu_transfer_helper_resource_create(struct pipe_screen *pscreen, 100bf215546Sopenharmony_ci const struct pipe_resource *templ) 101bf215546Sopenharmony_ci{ 102bf215546Sopenharmony_ci struct u_transfer_helper *helper = pscreen->transfer_helper; 103bf215546Sopenharmony_ci enum pipe_format format = templ->format; 104bf215546Sopenharmony_ci struct pipe_resource *prsc; 105bf215546Sopenharmony_ci 106bf215546Sopenharmony_ci if ((helper->separate_stencil && util_format_is_depth_and_stencil(format)) || 107bf215546Sopenharmony_ci (format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT && helper->separate_z32s8)) { 108bf215546Sopenharmony_ci struct pipe_resource t = *templ; 109bf215546Sopenharmony_ci struct pipe_resource *stencil; 110bf215546Sopenharmony_ci 111bf215546Sopenharmony_ci t.format = util_format_get_depth_only(format); 112bf215546Sopenharmony_ci 113bf215546Sopenharmony_ci prsc = helper->vtbl->resource_create(pscreen, &t); 114bf215546Sopenharmony_ci if (!prsc) 115bf215546Sopenharmony_ci return NULL; 116bf215546Sopenharmony_ci 117bf215546Sopenharmony_ci prsc->format = format; /* frob the format back to the "external" format */ 118bf215546Sopenharmony_ci 119bf215546Sopenharmony_ci t.format = PIPE_FORMAT_S8_UINT; 120bf215546Sopenharmony_ci stencil = helper->vtbl->resource_create(pscreen, &t); 121bf215546Sopenharmony_ci 122bf215546Sopenharmony_ci if (!stencil) { 123bf215546Sopenharmony_ci helper->vtbl->resource_destroy(pscreen, prsc); 124bf215546Sopenharmony_ci return NULL; 125bf215546Sopenharmony_ci } 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_ci helper->vtbl->set_stencil(prsc, stencil); 128bf215546Sopenharmony_ci } else if ((util_format_description(format)->layout == UTIL_FORMAT_LAYOUT_RGTC) && 129bf215546Sopenharmony_ci helper->fake_rgtc) { 130bf215546Sopenharmony_ci struct pipe_resource t = *templ; 131bf215546Sopenharmony_ci t.format = PIPE_FORMAT_R8G8B8A8_UNORM; 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_ci prsc = helper->vtbl->resource_create(pscreen, &t); 134bf215546Sopenharmony_ci if (!prsc) 135bf215546Sopenharmony_ci return NULL; 136bf215546Sopenharmony_ci 137bf215546Sopenharmony_ci prsc->format = format; /* frob the format back to the "external" format */ 138bf215546Sopenharmony_ci } else { 139bf215546Sopenharmony_ci /* normal case, no special handling: */ 140bf215546Sopenharmony_ci prsc = helper->vtbl->resource_create(pscreen, templ); 141bf215546Sopenharmony_ci if (!prsc) 142bf215546Sopenharmony_ci return NULL; 143bf215546Sopenharmony_ci } 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_ci return prsc; 146bf215546Sopenharmony_ci} 147bf215546Sopenharmony_ci 148bf215546Sopenharmony_civoid 149bf215546Sopenharmony_ciu_transfer_helper_resource_destroy(struct pipe_screen *pscreen, 150bf215546Sopenharmony_ci struct pipe_resource *prsc) 151bf215546Sopenharmony_ci{ 152bf215546Sopenharmony_ci struct u_transfer_helper *helper = pscreen->transfer_helper; 153bf215546Sopenharmony_ci 154bf215546Sopenharmony_ci if (helper->vtbl->get_stencil) { 155bf215546Sopenharmony_ci struct pipe_resource *stencil = helper->vtbl->get_stencil(prsc); 156bf215546Sopenharmony_ci 157bf215546Sopenharmony_ci pipe_resource_reference(&stencil, NULL); 158bf215546Sopenharmony_ci } 159bf215546Sopenharmony_ci 160bf215546Sopenharmony_ci helper->vtbl->resource_destroy(pscreen, prsc); 161bf215546Sopenharmony_ci} 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_cistatic bool needs_pack(unsigned usage) 164bf215546Sopenharmony_ci{ 165bf215546Sopenharmony_ci return (usage & PIPE_MAP_READ) && 166bf215546Sopenharmony_ci !(usage & (PIPE_MAP_DISCARD_WHOLE_RESOURCE | PIPE_MAP_DISCARD_RANGE)); 167bf215546Sopenharmony_ci} 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_ci/* In the case of transfer_map of a multi-sample resource, call back into 170bf215546Sopenharmony_ci * pctx->transfer_map() to map the staging resource, to handle cases of 171bf215546Sopenharmony_ci * MSAA + separate_z32s8 or fake_rgtc 172bf215546Sopenharmony_ci */ 173bf215546Sopenharmony_cistatic void * 174bf215546Sopenharmony_citransfer_map_msaa(struct pipe_context *pctx, 175bf215546Sopenharmony_ci struct pipe_resource *prsc, 176bf215546Sopenharmony_ci unsigned level, unsigned usage, 177bf215546Sopenharmony_ci const struct pipe_box *box, 178bf215546Sopenharmony_ci struct pipe_transfer **pptrans) 179bf215546Sopenharmony_ci{ 180bf215546Sopenharmony_ci struct pipe_screen *pscreen = pctx->screen; 181bf215546Sopenharmony_ci struct u_transfer *trans = calloc(1, sizeof(*trans)); 182bf215546Sopenharmony_ci if (!trans) 183bf215546Sopenharmony_ci return NULL; 184bf215546Sopenharmony_ci struct pipe_transfer *ptrans = &trans->base; 185bf215546Sopenharmony_ci 186bf215546Sopenharmony_ci pipe_resource_reference(&ptrans->resource, prsc); 187bf215546Sopenharmony_ci ptrans->level = level; 188bf215546Sopenharmony_ci ptrans->usage = usage; 189bf215546Sopenharmony_ci ptrans->box = *box; 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci struct pipe_resource tmpl = { 192bf215546Sopenharmony_ci .target = prsc->target, 193bf215546Sopenharmony_ci .format = prsc->format, 194bf215546Sopenharmony_ci .width0 = box->width, 195bf215546Sopenharmony_ci .height0 = box->height, 196bf215546Sopenharmony_ci .depth0 = 1, 197bf215546Sopenharmony_ci .array_size = 1, 198bf215546Sopenharmony_ci }; 199bf215546Sopenharmony_ci trans->ss = pscreen->resource_create(pscreen, &tmpl); 200bf215546Sopenharmony_ci if (!trans->ss) { 201bf215546Sopenharmony_ci free(trans); 202bf215546Sopenharmony_ci return NULL; 203bf215546Sopenharmony_ci } 204bf215546Sopenharmony_ci 205bf215546Sopenharmony_ci if (needs_pack(usage)) { 206bf215546Sopenharmony_ci struct pipe_blit_info blit; 207bf215546Sopenharmony_ci memset(&blit, 0, sizeof(blit)); 208bf215546Sopenharmony_ci 209bf215546Sopenharmony_ci blit.src.resource = ptrans->resource; 210bf215546Sopenharmony_ci blit.src.format = ptrans->resource->format; 211bf215546Sopenharmony_ci blit.src.level = ptrans->level; 212bf215546Sopenharmony_ci blit.src.box = *box; 213bf215546Sopenharmony_ci 214bf215546Sopenharmony_ci blit.dst.resource = trans->ss; 215bf215546Sopenharmony_ci blit.dst.format = trans->ss->format; 216bf215546Sopenharmony_ci blit.dst.box.width = box->width; 217bf215546Sopenharmony_ci blit.dst.box.height = box->height; 218bf215546Sopenharmony_ci blit.dst.box.depth = 1; 219bf215546Sopenharmony_ci 220bf215546Sopenharmony_ci blit.mask = util_format_get_mask(prsc->format); 221bf215546Sopenharmony_ci blit.filter = PIPE_TEX_FILTER_NEAREST; 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_ci pctx->blit(pctx, &blit); 224bf215546Sopenharmony_ci } 225bf215546Sopenharmony_ci 226bf215546Sopenharmony_ci struct pipe_box map_box = *box; 227bf215546Sopenharmony_ci map_box.x = 0; 228bf215546Sopenharmony_ci map_box.y = 0; 229bf215546Sopenharmony_ci 230bf215546Sopenharmony_ci void *ss_map = pctx->texture_map(pctx, trans->ss, 0, usage, &map_box, 231bf215546Sopenharmony_ci &trans->trans); 232bf215546Sopenharmony_ci if (!ss_map) { 233bf215546Sopenharmony_ci free(trans); 234bf215546Sopenharmony_ci return NULL; 235bf215546Sopenharmony_ci } 236bf215546Sopenharmony_ci 237bf215546Sopenharmony_ci ptrans->stride = trans->trans->stride; 238bf215546Sopenharmony_ci *pptrans = ptrans; 239bf215546Sopenharmony_ci return ss_map; 240bf215546Sopenharmony_ci} 241bf215546Sopenharmony_ci 242bf215546Sopenharmony_civoid * 243bf215546Sopenharmony_ciu_transfer_helper_transfer_map(struct pipe_context *pctx, 244bf215546Sopenharmony_ci struct pipe_resource *prsc, 245bf215546Sopenharmony_ci unsigned level, unsigned usage, 246bf215546Sopenharmony_ci const struct pipe_box *box, 247bf215546Sopenharmony_ci struct pipe_transfer **pptrans) 248bf215546Sopenharmony_ci{ 249bf215546Sopenharmony_ci struct u_transfer_helper *helper = pctx->screen->transfer_helper; 250bf215546Sopenharmony_ci struct u_transfer *trans; 251bf215546Sopenharmony_ci struct pipe_transfer *ptrans; 252bf215546Sopenharmony_ci enum pipe_format format = prsc->format; 253bf215546Sopenharmony_ci unsigned width = box->width; 254bf215546Sopenharmony_ci unsigned height = box->height; 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_ci if (!handle_transfer(prsc)) 257bf215546Sopenharmony_ci return helper->vtbl->transfer_map(pctx, prsc, level, usage, box, pptrans); 258bf215546Sopenharmony_ci 259bf215546Sopenharmony_ci if (helper->msaa_map && (prsc->nr_samples > 1)) 260bf215546Sopenharmony_ci return transfer_map_msaa(pctx, prsc, level, usage, box, pptrans); 261bf215546Sopenharmony_ci 262bf215546Sopenharmony_ci assert(box->depth == 1); 263bf215546Sopenharmony_ci 264bf215546Sopenharmony_ci trans = calloc(1, sizeof(*trans)); 265bf215546Sopenharmony_ci if (!trans) 266bf215546Sopenharmony_ci return NULL; 267bf215546Sopenharmony_ci 268bf215546Sopenharmony_ci ptrans = &trans->base; 269bf215546Sopenharmony_ci pipe_resource_reference(&ptrans->resource, prsc); 270bf215546Sopenharmony_ci ptrans->level = level; 271bf215546Sopenharmony_ci ptrans->usage = usage; 272bf215546Sopenharmony_ci ptrans->box = *box; 273bf215546Sopenharmony_ci ptrans->stride = util_format_get_stride(format, box->width); 274bf215546Sopenharmony_ci ptrans->layer_stride = ptrans->stride * box->height; 275bf215546Sopenharmony_ci 276bf215546Sopenharmony_ci trans->staging = malloc(ptrans->layer_stride); 277bf215546Sopenharmony_ci if (!trans->staging) 278bf215546Sopenharmony_ci goto fail; 279bf215546Sopenharmony_ci 280bf215546Sopenharmony_ci trans->ptr = helper->vtbl->transfer_map(pctx, prsc, level, usage, box, 281bf215546Sopenharmony_ci &trans->trans); 282bf215546Sopenharmony_ci if (!trans->ptr) 283bf215546Sopenharmony_ci goto fail; 284bf215546Sopenharmony_ci 285bf215546Sopenharmony_ci if (util_format_is_depth_and_stencil(prsc->format)) { 286bf215546Sopenharmony_ci struct pipe_resource *stencil = helper->vtbl->get_stencil(prsc); 287bf215546Sopenharmony_ci trans->ptr2 = helper->vtbl->transfer_map(pctx, stencil, level, 288bf215546Sopenharmony_ci usage, box, &trans->trans2); 289bf215546Sopenharmony_ci 290bf215546Sopenharmony_ci if (needs_pack(usage)) { 291bf215546Sopenharmony_ci switch (prsc->format) { 292bf215546Sopenharmony_ci case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: 293bf215546Sopenharmony_ci util_format_z32_float_s8x24_uint_pack_z_float(trans->staging, 294bf215546Sopenharmony_ci ptrans->stride, 295bf215546Sopenharmony_ci trans->ptr, 296bf215546Sopenharmony_ci trans->trans->stride, 297bf215546Sopenharmony_ci width, height); 298bf215546Sopenharmony_ci util_format_z32_float_s8x24_uint_pack_s_8uint(trans->staging, 299bf215546Sopenharmony_ci ptrans->stride, 300bf215546Sopenharmony_ci trans->ptr2, 301bf215546Sopenharmony_ci trans->trans2->stride, 302bf215546Sopenharmony_ci width, height); 303bf215546Sopenharmony_ci break; 304bf215546Sopenharmony_ci case PIPE_FORMAT_Z24_UNORM_S8_UINT: 305bf215546Sopenharmony_ci assert(!helper->z24_in_z32f); 306bf215546Sopenharmony_ci util_format_z24_unorm_s8_uint_pack_separate(trans->staging, 307bf215546Sopenharmony_ci ptrans->stride, 308bf215546Sopenharmony_ci trans->ptr, 309bf215546Sopenharmony_ci trans->trans->stride, 310bf215546Sopenharmony_ci trans->ptr2, 311bf215546Sopenharmony_ci trans->trans2->stride, 312bf215546Sopenharmony_ci width, height); 313bf215546Sopenharmony_ci break; 314bf215546Sopenharmony_ci default: 315bf215546Sopenharmony_ci unreachable("Unexpected format"); 316bf215546Sopenharmony_ci } 317bf215546Sopenharmony_ci } 318bf215546Sopenharmony_ci } else if (util_format_description(prsc->format)->layout == UTIL_FORMAT_LAYOUT_RGTC) { 319bf215546Sopenharmony_ci if (needs_pack(usage)) { 320bf215546Sopenharmony_ci switch (prsc->format) { 321bf215546Sopenharmony_ci case PIPE_FORMAT_RGTC1_UNORM: 322bf215546Sopenharmony_ci case PIPE_FORMAT_RGTC1_SNORM: 323bf215546Sopenharmony_ci case PIPE_FORMAT_LATC1_UNORM: 324bf215546Sopenharmony_ci case PIPE_FORMAT_LATC1_SNORM: 325bf215546Sopenharmony_ci util_format_rgtc1_unorm_pack_rgba_8unorm(trans->staging, 326bf215546Sopenharmony_ci ptrans->stride, 327bf215546Sopenharmony_ci trans->ptr, 328bf215546Sopenharmony_ci trans->trans->stride, 329bf215546Sopenharmony_ci width, height); 330bf215546Sopenharmony_ci break; 331bf215546Sopenharmony_ci case PIPE_FORMAT_RGTC2_UNORM: 332bf215546Sopenharmony_ci case PIPE_FORMAT_RGTC2_SNORM: 333bf215546Sopenharmony_ci case PIPE_FORMAT_LATC2_UNORM: 334bf215546Sopenharmony_ci case PIPE_FORMAT_LATC2_SNORM: 335bf215546Sopenharmony_ci util_format_rgtc2_unorm_pack_rgba_8unorm(trans->staging, 336bf215546Sopenharmony_ci ptrans->stride, 337bf215546Sopenharmony_ci trans->ptr, 338bf215546Sopenharmony_ci trans->trans->stride, 339bf215546Sopenharmony_ci width, height); 340bf215546Sopenharmony_ci break; 341bf215546Sopenharmony_ci default: 342bf215546Sopenharmony_ci assert(!"Unexpected format"); 343bf215546Sopenharmony_ci break; 344bf215546Sopenharmony_ci } 345bf215546Sopenharmony_ci } 346bf215546Sopenharmony_ci } else { 347bf215546Sopenharmony_ci unreachable("bleh"); 348bf215546Sopenharmony_ci } 349bf215546Sopenharmony_ci 350bf215546Sopenharmony_ci *pptrans = ptrans; 351bf215546Sopenharmony_ci return trans->staging; 352bf215546Sopenharmony_ci 353bf215546Sopenharmony_cifail: 354bf215546Sopenharmony_ci if (trans->trans) 355bf215546Sopenharmony_ci helper->vtbl->transfer_unmap(pctx, trans->trans); 356bf215546Sopenharmony_ci if (trans->trans2) 357bf215546Sopenharmony_ci helper->vtbl->transfer_unmap(pctx, trans->trans2); 358bf215546Sopenharmony_ci pipe_resource_reference(&ptrans->resource, NULL); 359bf215546Sopenharmony_ci free(trans->staging); 360bf215546Sopenharmony_ci free(trans); 361bf215546Sopenharmony_ci return NULL; 362bf215546Sopenharmony_ci} 363bf215546Sopenharmony_ci 364bf215546Sopenharmony_cistatic void 365bf215546Sopenharmony_ciflush_region(struct pipe_context *pctx, struct pipe_transfer *ptrans, 366bf215546Sopenharmony_ci const struct pipe_box *box) 367bf215546Sopenharmony_ci{ 368bf215546Sopenharmony_ci struct u_transfer_helper *helper = pctx->screen->transfer_helper; 369bf215546Sopenharmony_ci /* using the function here hits an assert for the deinterleave cases */ 370bf215546Sopenharmony_ci struct u_transfer *trans = (struct u_transfer *)ptrans; 371bf215546Sopenharmony_ci enum pipe_format iformat, format = ptrans->resource->format; 372bf215546Sopenharmony_ci unsigned width = box->width; 373bf215546Sopenharmony_ci unsigned height = box->height; 374bf215546Sopenharmony_ci void *src, *dst; 375bf215546Sopenharmony_ci 376bf215546Sopenharmony_ci if (!(ptrans->usage & PIPE_MAP_WRITE)) 377bf215546Sopenharmony_ci return; 378bf215546Sopenharmony_ci 379bf215546Sopenharmony_ci if (trans->ss) { 380bf215546Sopenharmony_ci struct pipe_blit_info blit; 381bf215546Sopenharmony_ci memset(&blit, 0, sizeof(blit)); 382bf215546Sopenharmony_ci 383bf215546Sopenharmony_ci blit.src.resource = trans->ss; 384bf215546Sopenharmony_ci blit.src.format = trans->ss->format; 385bf215546Sopenharmony_ci blit.src.box = *box; 386bf215546Sopenharmony_ci 387bf215546Sopenharmony_ci blit.dst.resource = ptrans->resource; 388bf215546Sopenharmony_ci blit.dst.format = ptrans->resource->format; 389bf215546Sopenharmony_ci blit.dst.level = ptrans->level; 390bf215546Sopenharmony_ci 391bf215546Sopenharmony_ci u_box_2d(ptrans->box.x + box->x, 392bf215546Sopenharmony_ci ptrans->box.y + box->y, 393bf215546Sopenharmony_ci box->width, box->height, 394bf215546Sopenharmony_ci &blit.dst.box); 395bf215546Sopenharmony_ci 396bf215546Sopenharmony_ci blit.mask = util_format_get_mask(ptrans->resource->format); 397bf215546Sopenharmony_ci blit.filter = PIPE_TEX_FILTER_NEAREST; 398bf215546Sopenharmony_ci 399bf215546Sopenharmony_ci pctx->blit(pctx, &blit); 400bf215546Sopenharmony_ci 401bf215546Sopenharmony_ci return; 402bf215546Sopenharmony_ci } 403bf215546Sopenharmony_ci 404bf215546Sopenharmony_ci iformat = helper->vtbl->get_internal_format(ptrans->resource); 405bf215546Sopenharmony_ci 406bf215546Sopenharmony_ci src = (uint8_t *)trans->staging + 407bf215546Sopenharmony_ci (box->y * ptrans->stride) + 408bf215546Sopenharmony_ci (box->x * util_format_get_blocksize(format)); 409bf215546Sopenharmony_ci dst = (uint8_t *)trans->ptr + 410bf215546Sopenharmony_ci (box->y * trans->trans->stride) + 411bf215546Sopenharmony_ci (box->x * util_format_get_blocksize(iformat)); 412bf215546Sopenharmony_ci 413bf215546Sopenharmony_ci switch (format) { 414bf215546Sopenharmony_ci case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: 415bf215546Sopenharmony_ci util_format_z32_float_s8x24_uint_unpack_z_float(dst, 416bf215546Sopenharmony_ci trans->trans->stride, 417bf215546Sopenharmony_ci src, 418bf215546Sopenharmony_ci ptrans->stride, 419bf215546Sopenharmony_ci width, height); 420bf215546Sopenharmony_ci FALLTHROUGH; 421bf215546Sopenharmony_ci case PIPE_FORMAT_X32_S8X24_UINT: 422bf215546Sopenharmony_ci dst = (uint8_t *)trans->ptr2 + 423bf215546Sopenharmony_ci (box->y * trans->trans2->stride) + 424bf215546Sopenharmony_ci (box->x * util_format_get_blocksize(PIPE_FORMAT_S8_UINT)); 425bf215546Sopenharmony_ci 426bf215546Sopenharmony_ci util_format_z32_float_s8x24_uint_unpack_s_8uint(dst, 427bf215546Sopenharmony_ci trans->trans2->stride, 428bf215546Sopenharmony_ci src, 429bf215546Sopenharmony_ci ptrans->stride, 430bf215546Sopenharmony_ci width, height); 431bf215546Sopenharmony_ci break; 432bf215546Sopenharmony_ci case PIPE_FORMAT_Z24X8_UNORM: 433bf215546Sopenharmony_ci util_format_z24x8_unorm_unpack_z_float(dst, trans->trans->stride, 434bf215546Sopenharmony_ci src, ptrans->stride, 435bf215546Sopenharmony_ci width, height); 436bf215546Sopenharmony_ci break; 437bf215546Sopenharmony_ci case PIPE_FORMAT_Z24_UNORM_S8_UINT: 438bf215546Sopenharmony_ci if (helper->z24_in_z32f) { 439bf215546Sopenharmony_ci util_format_z24_unorm_s8_uint_unpack_z_float(dst, trans->trans->stride, 440bf215546Sopenharmony_ci src, ptrans->stride, 441bf215546Sopenharmony_ci width, height); 442bf215546Sopenharmony_ci } else { 443bf215546Sopenharmony_ci /* just do a strided 32-bit copy for depth; s8 can become garbage x8 */ 444bf215546Sopenharmony_ci util_format_z32_unorm_unpack_z_32unorm(dst, trans->trans->stride, 445bf215546Sopenharmony_ci src, ptrans->stride, 446bf215546Sopenharmony_ci width, height); 447bf215546Sopenharmony_ci } 448bf215546Sopenharmony_ci FALLTHROUGH; 449bf215546Sopenharmony_ci case PIPE_FORMAT_X24S8_UINT: 450bf215546Sopenharmony_ci dst = (uint8_t *)trans->ptr2 + 451bf215546Sopenharmony_ci (box->y * trans->trans2->stride) + 452bf215546Sopenharmony_ci (box->x * util_format_get_blocksize(PIPE_FORMAT_S8_UINT)); 453bf215546Sopenharmony_ci 454bf215546Sopenharmony_ci util_format_z24_unorm_s8_uint_unpack_s_8uint(dst, trans->trans2->stride, 455bf215546Sopenharmony_ci src, ptrans->stride, 456bf215546Sopenharmony_ci width, height); 457bf215546Sopenharmony_ci break; 458bf215546Sopenharmony_ci 459bf215546Sopenharmony_ci case PIPE_FORMAT_RGTC1_UNORM: 460bf215546Sopenharmony_ci case PIPE_FORMAT_RGTC1_SNORM: 461bf215546Sopenharmony_ci case PIPE_FORMAT_LATC1_UNORM: 462bf215546Sopenharmony_ci case PIPE_FORMAT_LATC1_SNORM: 463bf215546Sopenharmony_ci util_format_rgtc1_unorm_unpack_rgba_8unorm(dst, 464bf215546Sopenharmony_ci trans->trans->stride, 465bf215546Sopenharmony_ci src, 466bf215546Sopenharmony_ci ptrans->stride, 467bf215546Sopenharmony_ci width, height); 468bf215546Sopenharmony_ci break; 469bf215546Sopenharmony_ci case PIPE_FORMAT_RGTC2_UNORM: 470bf215546Sopenharmony_ci case PIPE_FORMAT_RGTC2_SNORM: 471bf215546Sopenharmony_ci case PIPE_FORMAT_LATC2_UNORM: 472bf215546Sopenharmony_ci case PIPE_FORMAT_LATC2_SNORM: 473bf215546Sopenharmony_ci util_format_rgtc2_unorm_unpack_rgba_8unorm(dst, 474bf215546Sopenharmony_ci trans->trans->stride, 475bf215546Sopenharmony_ci src, 476bf215546Sopenharmony_ci ptrans->stride, 477bf215546Sopenharmony_ci width, height); 478bf215546Sopenharmony_ci break; 479bf215546Sopenharmony_ci default: 480bf215546Sopenharmony_ci assert(!"Unexpected staging transfer type"); 481bf215546Sopenharmony_ci break; 482bf215546Sopenharmony_ci } 483bf215546Sopenharmony_ci} 484bf215546Sopenharmony_ci 485bf215546Sopenharmony_civoid 486bf215546Sopenharmony_ciu_transfer_helper_transfer_flush_region(struct pipe_context *pctx, 487bf215546Sopenharmony_ci struct pipe_transfer *ptrans, 488bf215546Sopenharmony_ci const struct pipe_box *box) 489bf215546Sopenharmony_ci{ 490bf215546Sopenharmony_ci struct u_transfer_helper *helper = pctx->screen->transfer_helper; 491bf215546Sopenharmony_ci 492bf215546Sopenharmony_ci if (handle_transfer(ptrans->resource)) { 493bf215546Sopenharmony_ci struct u_transfer *trans = u_transfer(ptrans); 494bf215546Sopenharmony_ci 495bf215546Sopenharmony_ci /* handle MSAA case, since there could be multiple levels of 496bf215546Sopenharmony_ci * wrapped transfer, call pctx->transfer_flush_region() 497bf215546Sopenharmony_ci * instead of helper->vtbl->transfer_flush_region() 498bf215546Sopenharmony_ci */ 499bf215546Sopenharmony_ci if (trans->ss) { 500bf215546Sopenharmony_ci pctx->transfer_flush_region(pctx, trans->trans, box); 501bf215546Sopenharmony_ci flush_region(pctx, ptrans, box); 502bf215546Sopenharmony_ci return; 503bf215546Sopenharmony_ci } 504bf215546Sopenharmony_ci 505bf215546Sopenharmony_ci flush_region(pctx, ptrans, box); 506bf215546Sopenharmony_ci 507bf215546Sopenharmony_ci helper->vtbl->transfer_flush_region(pctx, trans->trans, box); 508bf215546Sopenharmony_ci if (trans->trans2) 509bf215546Sopenharmony_ci helper->vtbl->transfer_flush_region(pctx, trans->trans2, box); 510bf215546Sopenharmony_ci 511bf215546Sopenharmony_ci } else { 512bf215546Sopenharmony_ci helper->vtbl->transfer_flush_region(pctx, ptrans, box); 513bf215546Sopenharmony_ci } 514bf215546Sopenharmony_ci} 515bf215546Sopenharmony_ci 516bf215546Sopenharmony_civoid 517bf215546Sopenharmony_ciu_transfer_helper_transfer_unmap(struct pipe_context *pctx, 518bf215546Sopenharmony_ci struct pipe_transfer *ptrans) 519bf215546Sopenharmony_ci{ 520bf215546Sopenharmony_ci struct u_transfer_helper *helper = pctx->screen->transfer_helper; 521bf215546Sopenharmony_ci 522bf215546Sopenharmony_ci if (handle_transfer(ptrans->resource)) { 523bf215546Sopenharmony_ci struct u_transfer *trans = u_transfer(ptrans); 524bf215546Sopenharmony_ci 525bf215546Sopenharmony_ci if (!(ptrans->usage & PIPE_MAP_FLUSH_EXPLICIT)) { 526bf215546Sopenharmony_ci struct pipe_box box; 527bf215546Sopenharmony_ci u_box_2d(0, 0, ptrans->box.width, ptrans->box.height, &box); 528bf215546Sopenharmony_ci if (trans->ss) 529bf215546Sopenharmony_ci pctx->transfer_flush_region(pctx, trans->trans, &box); 530bf215546Sopenharmony_ci flush_region(pctx, ptrans, &box); 531bf215546Sopenharmony_ci } 532bf215546Sopenharmony_ci 533bf215546Sopenharmony_ci /* in MSAA case, there could be multiple levels of wrapping 534bf215546Sopenharmony_ci * so don't call helper->vtbl->transfer_unmap() directly 535bf215546Sopenharmony_ci */ 536bf215546Sopenharmony_ci if (trans->ss) { 537bf215546Sopenharmony_ci pctx->texture_unmap(pctx, trans->trans); 538bf215546Sopenharmony_ci pipe_resource_reference(&trans->ss, NULL); 539bf215546Sopenharmony_ci } else { 540bf215546Sopenharmony_ci helper->vtbl->transfer_unmap(pctx, trans->trans); 541bf215546Sopenharmony_ci if (trans->trans2) 542bf215546Sopenharmony_ci helper->vtbl->transfer_unmap(pctx, trans->trans2); 543bf215546Sopenharmony_ci } 544bf215546Sopenharmony_ci 545bf215546Sopenharmony_ci pipe_resource_reference(&ptrans->resource, NULL); 546bf215546Sopenharmony_ci 547bf215546Sopenharmony_ci free(trans->staging); 548bf215546Sopenharmony_ci free(trans); 549bf215546Sopenharmony_ci } else { 550bf215546Sopenharmony_ci helper->vtbl->transfer_unmap(pctx, ptrans); 551bf215546Sopenharmony_ci } 552bf215546Sopenharmony_ci} 553bf215546Sopenharmony_ci 554bf215546Sopenharmony_cistruct u_transfer_helper * 555bf215546Sopenharmony_ciu_transfer_helper_create(const struct u_transfer_vtbl *vtbl, 556bf215546Sopenharmony_ci bool separate_z32s8, 557bf215546Sopenharmony_ci bool separate_stencil, 558bf215546Sopenharmony_ci bool fake_rgtc, 559bf215546Sopenharmony_ci bool msaa_map, 560bf215546Sopenharmony_ci bool z24_in_z32f) 561bf215546Sopenharmony_ci{ 562bf215546Sopenharmony_ci struct u_transfer_helper *helper = calloc(1, sizeof(*helper)); 563bf215546Sopenharmony_ci 564bf215546Sopenharmony_ci helper->vtbl = vtbl; 565bf215546Sopenharmony_ci helper->separate_z32s8 = separate_z32s8; 566bf215546Sopenharmony_ci helper->separate_stencil = separate_stencil; 567bf215546Sopenharmony_ci helper->fake_rgtc = fake_rgtc; 568bf215546Sopenharmony_ci helper->msaa_map = msaa_map; 569bf215546Sopenharmony_ci helper->z24_in_z32f = z24_in_z32f; 570bf215546Sopenharmony_ci 571bf215546Sopenharmony_ci return helper; 572bf215546Sopenharmony_ci} 573bf215546Sopenharmony_ci 574bf215546Sopenharmony_civoid 575bf215546Sopenharmony_ciu_transfer_helper_destroy(struct u_transfer_helper *helper) 576bf215546Sopenharmony_ci{ 577bf215546Sopenharmony_ci free(helper); 578bf215546Sopenharmony_ci} 579bf215546Sopenharmony_ci 580bf215546Sopenharmony_ci 581bf215546Sopenharmony_ci/* these two functions 'deinterleave' are meant to be used without the corresponding 582bf215546Sopenharmony_ci * resource_create/destroy hooks, as they perform the interleaving on-the-fly 583bf215546Sopenharmony_ci * 584bf215546Sopenharmony_ci * drivers should expect to be passed the same buffer repeatedly with the format changed 585bf215546Sopenharmony_ci * to indicate which component is being mapped 586bf215546Sopenharmony_ci */ 587bf215546Sopenharmony_civoid * 588bf215546Sopenharmony_ciu_transfer_helper_deinterleave_transfer_map(struct pipe_context *pctx, 589bf215546Sopenharmony_ci struct pipe_resource *prsc, 590bf215546Sopenharmony_ci unsigned level, unsigned usage, 591bf215546Sopenharmony_ci const struct pipe_box *box, 592bf215546Sopenharmony_ci struct pipe_transfer **pptrans) 593bf215546Sopenharmony_ci{ 594bf215546Sopenharmony_ci struct u_transfer_helper *helper = pctx->screen->transfer_helper; 595bf215546Sopenharmony_ci struct u_transfer *trans; 596bf215546Sopenharmony_ci struct pipe_transfer *ptrans; 597bf215546Sopenharmony_ci enum pipe_format format = prsc->format; 598bf215546Sopenharmony_ci unsigned width = box->width; 599bf215546Sopenharmony_ci unsigned height = box->height; 600bf215546Sopenharmony_ci 601bf215546Sopenharmony_ci if (!need_interleave_path(helper, format)) 602bf215546Sopenharmony_ci return helper->vtbl->transfer_map(pctx, prsc, level, usage, box, pptrans); 603bf215546Sopenharmony_ci 604bf215546Sopenharmony_ci assert(box->depth == 1); 605bf215546Sopenharmony_ci 606bf215546Sopenharmony_ci trans = calloc(1, sizeof(*trans)); 607bf215546Sopenharmony_ci if (!trans) 608bf215546Sopenharmony_ci return NULL; 609bf215546Sopenharmony_ci 610bf215546Sopenharmony_ci ptrans = &trans->base; 611bf215546Sopenharmony_ci pipe_resource_reference(&ptrans->resource, prsc); 612bf215546Sopenharmony_ci ptrans->level = level; 613bf215546Sopenharmony_ci ptrans->usage = usage; 614bf215546Sopenharmony_ci ptrans->box = *box; 615bf215546Sopenharmony_ci ptrans->stride = util_format_get_stride(format, box->width); 616bf215546Sopenharmony_ci ptrans->layer_stride = ptrans->stride * box->height; 617bf215546Sopenharmony_ci 618bf215546Sopenharmony_ci bool has_stencil = util_format_is_depth_and_stencil(format); 619bf215546Sopenharmony_ci 620bf215546Sopenharmony_ci trans->staging = malloc(ptrans->layer_stride); 621bf215546Sopenharmony_ci if (!trans->staging) 622bf215546Sopenharmony_ci goto fail; 623bf215546Sopenharmony_ci 624bf215546Sopenharmony_ci trans->ptr = helper->vtbl->transfer_map(pctx, prsc, level, usage | PIPE_MAP_DEPTH_ONLY, box, 625bf215546Sopenharmony_ci &trans->trans); 626bf215546Sopenharmony_ci if (!trans->ptr) 627bf215546Sopenharmony_ci goto fail; 628bf215546Sopenharmony_ci 629bf215546Sopenharmony_ci trans->ptr2 = NULL; 630bf215546Sopenharmony_ci if (has_stencil) 631bf215546Sopenharmony_ci trans->ptr2 = helper->vtbl->transfer_map(pctx, prsc, level, 632bf215546Sopenharmony_ci usage | PIPE_MAP_STENCIL_ONLY, box, &trans->trans2); 633bf215546Sopenharmony_ci if (needs_pack(usage)) { 634bf215546Sopenharmony_ci switch (prsc->format) { 635bf215546Sopenharmony_ci case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: 636bf215546Sopenharmony_ci util_format_z32_float_s8x24_uint_pack_z_float(trans->staging, 637bf215546Sopenharmony_ci ptrans->stride, 638bf215546Sopenharmony_ci trans->ptr, 639bf215546Sopenharmony_ci trans->trans->stride, 640bf215546Sopenharmony_ci width, height); 641bf215546Sopenharmony_ci util_format_z32_float_s8x24_uint_pack_s_8uint(trans->staging, 642bf215546Sopenharmony_ci ptrans->stride, 643bf215546Sopenharmony_ci trans->ptr2, 644bf215546Sopenharmony_ci trans->trans2->stride, 645bf215546Sopenharmony_ci width, height); 646bf215546Sopenharmony_ci break; 647bf215546Sopenharmony_ci case PIPE_FORMAT_Z24_UNORM_S8_UINT: 648bf215546Sopenharmony_ci if (helper->z24_in_z32f) { 649bf215546Sopenharmony_ci util_format_z24_unorm_s8_uint_pack_separate_z32(trans->staging, 650bf215546Sopenharmony_ci ptrans->stride, 651bf215546Sopenharmony_ci trans->ptr, 652bf215546Sopenharmony_ci trans->trans->stride, 653bf215546Sopenharmony_ci trans->ptr2, 654bf215546Sopenharmony_ci trans->trans2->stride, 655bf215546Sopenharmony_ci width, height); 656bf215546Sopenharmony_ci } else { 657bf215546Sopenharmony_ci util_format_z24_unorm_s8_uint_pack_separate(trans->staging, 658bf215546Sopenharmony_ci ptrans->stride, 659bf215546Sopenharmony_ci trans->ptr, 660bf215546Sopenharmony_ci trans->trans->stride, 661bf215546Sopenharmony_ci trans->ptr2, 662bf215546Sopenharmony_ci trans->trans2->stride, 663bf215546Sopenharmony_ci width, height); 664bf215546Sopenharmony_ci } 665bf215546Sopenharmony_ci break; 666bf215546Sopenharmony_ci case PIPE_FORMAT_Z24X8_UNORM: 667bf215546Sopenharmony_ci assert(helper->z24_in_z32f); 668bf215546Sopenharmony_ci util_format_z24x8_unorm_pack_z_float(trans->staging, ptrans->stride, 669bf215546Sopenharmony_ci trans->ptr, trans->trans->stride, 670bf215546Sopenharmony_ci width, height); 671bf215546Sopenharmony_ci break; 672bf215546Sopenharmony_ci default: 673bf215546Sopenharmony_ci unreachable("Unexpected format"); 674bf215546Sopenharmony_ci } 675bf215546Sopenharmony_ci } 676bf215546Sopenharmony_ci 677bf215546Sopenharmony_ci *pptrans = ptrans; 678bf215546Sopenharmony_ci return trans->staging; 679bf215546Sopenharmony_ci 680bf215546Sopenharmony_cifail: 681bf215546Sopenharmony_ci if (trans->trans) 682bf215546Sopenharmony_ci helper->vtbl->transfer_unmap(pctx, trans->trans); 683bf215546Sopenharmony_ci if (trans->trans2) 684bf215546Sopenharmony_ci helper->vtbl->transfer_unmap(pctx, trans->trans2); 685bf215546Sopenharmony_ci pipe_resource_reference(&ptrans->resource, NULL); 686bf215546Sopenharmony_ci free(trans->staging); 687bf215546Sopenharmony_ci free(trans); 688bf215546Sopenharmony_ci return NULL; 689bf215546Sopenharmony_ci} 690bf215546Sopenharmony_ci 691bf215546Sopenharmony_civoid 692bf215546Sopenharmony_ciu_transfer_helper_deinterleave_transfer_unmap(struct pipe_context *pctx, 693bf215546Sopenharmony_ci struct pipe_transfer *ptrans) 694bf215546Sopenharmony_ci{ 695bf215546Sopenharmony_ci struct u_transfer_helper *helper = pctx->screen->transfer_helper; 696bf215546Sopenharmony_ci enum pipe_format format = ptrans->resource->format; 697bf215546Sopenharmony_ci 698bf215546Sopenharmony_ci if (!need_interleave_path(helper, format)) { 699bf215546Sopenharmony_ci helper->vtbl->transfer_unmap(pctx, ptrans); 700bf215546Sopenharmony_ci return; 701bf215546Sopenharmony_ci } 702bf215546Sopenharmony_ci 703bf215546Sopenharmony_ci struct u_transfer *trans = (struct u_transfer *)ptrans; 704bf215546Sopenharmony_ci 705bf215546Sopenharmony_ci if (!(ptrans->usage & PIPE_MAP_FLUSH_EXPLICIT)) { 706bf215546Sopenharmony_ci struct pipe_box box; 707bf215546Sopenharmony_ci u_box_2d(0, 0, ptrans->box.width, ptrans->box.height, &box); 708bf215546Sopenharmony_ci flush_region(pctx, ptrans, &box); 709bf215546Sopenharmony_ci } 710bf215546Sopenharmony_ci 711bf215546Sopenharmony_ci helper->vtbl->transfer_unmap(pctx, trans->trans); 712bf215546Sopenharmony_ci if (trans->trans2) 713bf215546Sopenharmony_ci helper->vtbl->transfer_unmap(pctx, trans->trans2); 714bf215546Sopenharmony_ci 715bf215546Sopenharmony_ci pipe_resource_reference(&ptrans->resource, NULL); 716bf215546Sopenharmony_ci 717bf215546Sopenharmony_ci free(trans->staging); 718bf215546Sopenharmony_ci free(trans); 719bf215546Sopenharmony_ci} 720