1bf215546Sopenharmony_ci/************************************************************************** 2bf215546Sopenharmony_ci * 3bf215546Sopenharmony_ci * Copyright 2012 Marek Olšák <maraeo@gmail.com> 4bf215546Sopenharmony_ci * All Rights Reserved. 5bf215546Sopenharmony_ci * 6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the 8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 12bf215546Sopenharmony_ci * the following conditions: 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the 15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 16bf215546Sopenharmony_ci * of the Software. 17bf215546Sopenharmony_ci * 18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21bf215546Sopenharmony_ci * IN NO EVENT SHALL THE AUTHORS AND/OR THEIR SUPPLIERS BE LIABLE FOR 22bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci **************************************************************************/ 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci#include "util/format/format_utils.h" 29bf215546Sopenharmony_ci#include "util/u_cpu_detect.h" 30bf215546Sopenharmony_ci#include "util/u_helpers.h" 31bf215546Sopenharmony_ci#include "util/u_inlines.h" 32bf215546Sopenharmony_ci#include "util/u_upload_mgr.h" 33bf215546Sopenharmony_ci#include "util/u_thread.h" 34bf215546Sopenharmony_ci#include "util/os_time.h" 35bf215546Sopenharmony_ci#include <inttypes.h> 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_ci/** 38bf215546Sopenharmony_ci * This function is used to copy an array of pipe_vertex_buffer structures, 39bf215546Sopenharmony_ci * while properly referencing the pipe_vertex_buffer::buffer member. 40bf215546Sopenharmony_ci * 41bf215546Sopenharmony_ci * enabled_buffers is updated such that the bits corresponding to the indices 42bf215546Sopenharmony_ci * of disabled buffers are set to 0 and the enabled ones are set to 1. 43bf215546Sopenharmony_ci * 44bf215546Sopenharmony_ci * \sa util_copy_framebuffer_state 45bf215546Sopenharmony_ci */ 46bf215546Sopenharmony_civoid util_set_vertex_buffers_mask(struct pipe_vertex_buffer *dst, 47bf215546Sopenharmony_ci uint32_t *enabled_buffers, 48bf215546Sopenharmony_ci const struct pipe_vertex_buffer *src, 49bf215546Sopenharmony_ci unsigned start_slot, unsigned count, 50bf215546Sopenharmony_ci unsigned unbind_num_trailing_slots, 51bf215546Sopenharmony_ci bool take_ownership) 52bf215546Sopenharmony_ci{ 53bf215546Sopenharmony_ci unsigned i; 54bf215546Sopenharmony_ci uint32_t bitmask = 0; 55bf215546Sopenharmony_ci 56bf215546Sopenharmony_ci dst += start_slot; 57bf215546Sopenharmony_ci 58bf215546Sopenharmony_ci *enabled_buffers &= ~u_bit_consecutive(start_slot, count); 59bf215546Sopenharmony_ci 60bf215546Sopenharmony_ci if (src) { 61bf215546Sopenharmony_ci for (i = 0; i < count; i++) { 62bf215546Sopenharmony_ci if (src[i].buffer.resource) 63bf215546Sopenharmony_ci bitmask |= 1 << i; 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_ci pipe_vertex_buffer_unreference(&dst[i]); 66bf215546Sopenharmony_ci 67bf215546Sopenharmony_ci if (!take_ownership && !src[i].is_user_buffer) 68bf215546Sopenharmony_ci pipe_resource_reference(&dst[i].buffer.resource, src[i].buffer.resource); 69bf215546Sopenharmony_ci } 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_ci /* Copy over the other members of pipe_vertex_buffer. */ 72bf215546Sopenharmony_ci memcpy(dst, src, count * sizeof(struct pipe_vertex_buffer)); 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_ci *enabled_buffers |= bitmask << start_slot; 75bf215546Sopenharmony_ci } 76bf215546Sopenharmony_ci else { 77bf215546Sopenharmony_ci /* Unreference the buffers. */ 78bf215546Sopenharmony_ci for (i = 0; i < count; i++) 79bf215546Sopenharmony_ci pipe_vertex_buffer_unreference(&dst[i]); 80bf215546Sopenharmony_ci } 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_ci for (i = 0; i < unbind_num_trailing_slots; i++) 83bf215546Sopenharmony_ci pipe_vertex_buffer_unreference(&dst[count + i]); 84bf215546Sopenharmony_ci} 85bf215546Sopenharmony_ci 86bf215546Sopenharmony_ci/** 87bf215546Sopenharmony_ci * Same as util_set_vertex_buffers_mask, but it only returns the number 88bf215546Sopenharmony_ci * of bound buffers. 89bf215546Sopenharmony_ci */ 90bf215546Sopenharmony_civoid util_set_vertex_buffers_count(struct pipe_vertex_buffer *dst, 91bf215546Sopenharmony_ci unsigned *dst_count, 92bf215546Sopenharmony_ci const struct pipe_vertex_buffer *src, 93bf215546Sopenharmony_ci unsigned start_slot, unsigned count, 94bf215546Sopenharmony_ci unsigned unbind_num_trailing_slots, 95bf215546Sopenharmony_ci bool take_ownership) 96bf215546Sopenharmony_ci{ 97bf215546Sopenharmony_ci unsigned i; 98bf215546Sopenharmony_ci uint32_t enabled_buffers = 0; 99bf215546Sopenharmony_ci 100bf215546Sopenharmony_ci for (i = 0; i < *dst_count; i++) { 101bf215546Sopenharmony_ci if (dst[i].buffer.resource) 102bf215546Sopenharmony_ci enabled_buffers |= (1ull << i); 103bf215546Sopenharmony_ci } 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci util_set_vertex_buffers_mask(dst, &enabled_buffers, src, start_slot, 106bf215546Sopenharmony_ci count, unbind_num_trailing_slots, 107bf215546Sopenharmony_ci take_ownership); 108bf215546Sopenharmony_ci 109bf215546Sopenharmony_ci *dst_count = util_last_bit(enabled_buffers); 110bf215546Sopenharmony_ci} 111bf215546Sopenharmony_ci 112bf215546Sopenharmony_ci/** 113bf215546Sopenharmony_ci * This function is used to copy an array of pipe_shader_buffer structures, 114bf215546Sopenharmony_ci * while properly referencing the pipe_shader_buffer::buffer member. 115bf215546Sopenharmony_ci * 116bf215546Sopenharmony_ci * \sa util_set_vertex_buffer_mask 117bf215546Sopenharmony_ci */ 118bf215546Sopenharmony_civoid util_set_shader_buffers_mask(struct pipe_shader_buffer *dst, 119bf215546Sopenharmony_ci uint32_t *enabled_buffers, 120bf215546Sopenharmony_ci const struct pipe_shader_buffer *src, 121bf215546Sopenharmony_ci unsigned start_slot, unsigned count) 122bf215546Sopenharmony_ci{ 123bf215546Sopenharmony_ci unsigned i; 124bf215546Sopenharmony_ci 125bf215546Sopenharmony_ci dst += start_slot; 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_ci if (src) { 128bf215546Sopenharmony_ci for (i = 0; i < count; i++) { 129bf215546Sopenharmony_ci pipe_resource_reference(&dst[i].buffer, src[i].buffer); 130bf215546Sopenharmony_ci 131bf215546Sopenharmony_ci if (src[i].buffer) 132bf215546Sopenharmony_ci *enabled_buffers |= (1ull << (start_slot + i)); 133bf215546Sopenharmony_ci else 134bf215546Sopenharmony_ci *enabled_buffers &= ~(1ull << (start_slot + i)); 135bf215546Sopenharmony_ci } 136bf215546Sopenharmony_ci 137bf215546Sopenharmony_ci /* Copy over the other members of pipe_shader_buffer. */ 138bf215546Sopenharmony_ci memcpy(dst, src, count * sizeof(struct pipe_shader_buffer)); 139bf215546Sopenharmony_ci } 140bf215546Sopenharmony_ci else { 141bf215546Sopenharmony_ci /* Unreference the buffers. */ 142bf215546Sopenharmony_ci for (i = 0; i < count; i++) 143bf215546Sopenharmony_ci pipe_resource_reference(&dst[i].buffer, NULL); 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_ci *enabled_buffers &= ~(((1ull << count) - 1) << start_slot); 146bf215546Sopenharmony_ci } 147bf215546Sopenharmony_ci} 148bf215546Sopenharmony_ci 149bf215546Sopenharmony_ci/** 150bf215546Sopenharmony_ci * Given a user index buffer, save the structure to "saved", and upload it. 151bf215546Sopenharmony_ci */ 152bf215546Sopenharmony_cibool 153bf215546Sopenharmony_ciutil_upload_index_buffer(struct pipe_context *pipe, 154bf215546Sopenharmony_ci const struct pipe_draw_info *info, 155bf215546Sopenharmony_ci const struct pipe_draw_start_count_bias *draw, 156bf215546Sopenharmony_ci struct pipe_resource **out_buffer, 157bf215546Sopenharmony_ci unsigned *out_offset, unsigned alignment) 158bf215546Sopenharmony_ci{ 159bf215546Sopenharmony_ci unsigned start_offset = draw->start * info->index_size; 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci u_upload_data(pipe->stream_uploader, start_offset, 162bf215546Sopenharmony_ci draw->count * info->index_size, alignment, 163bf215546Sopenharmony_ci (char*)info->index.user + start_offset, 164bf215546Sopenharmony_ci out_offset, out_buffer); 165bf215546Sopenharmony_ci u_upload_unmap(pipe->stream_uploader); 166bf215546Sopenharmony_ci *out_offset -= start_offset; 167bf215546Sopenharmony_ci return *out_buffer != NULL; 168bf215546Sopenharmony_ci} 169bf215546Sopenharmony_ci 170bf215546Sopenharmony_ci/** 171bf215546Sopenharmony_ci * Lower each UINT64 vertex element to 1 or 2 UINT32 vertex elements. 172bf215546Sopenharmony_ci * 3 and 4 component formats are expanded into 2 slots. 173bf215546Sopenharmony_ci * 174bf215546Sopenharmony_ci * @param velems Original vertex elements, will be updated to contain 175bf215546Sopenharmony_ci * the lowered vertex elements. 176bf215546Sopenharmony_ci * @param velem_count Original count, will be updated to contain the count 177bf215546Sopenharmony_ci * after lowering. 178bf215546Sopenharmony_ci * @param tmp Temporary array of PIPE_MAX_ATTRIBS vertex elements. 179bf215546Sopenharmony_ci */ 180bf215546Sopenharmony_civoid 181bf215546Sopenharmony_ciutil_lower_uint64_vertex_elements(const struct pipe_vertex_element **velems, 182bf215546Sopenharmony_ci unsigned *velem_count, 183bf215546Sopenharmony_ci struct pipe_vertex_element tmp[PIPE_MAX_ATTRIBS]) 184bf215546Sopenharmony_ci{ 185bf215546Sopenharmony_ci const struct pipe_vertex_element *input = *velems; 186bf215546Sopenharmony_ci unsigned count = *velem_count; 187bf215546Sopenharmony_ci bool has_64bit = false; 188bf215546Sopenharmony_ci 189bf215546Sopenharmony_ci for (unsigned i = 0; i < count; i++) { 190bf215546Sopenharmony_ci has_64bit |= input[i].src_format >= PIPE_FORMAT_R64_UINT && 191bf215546Sopenharmony_ci input[i].src_format <= PIPE_FORMAT_R64G64B64A64_UINT; 192bf215546Sopenharmony_ci } 193bf215546Sopenharmony_ci 194bf215546Sopenharmony_ci /* Return the original vertex elements if there is nothing to do. */ 195bf215546Sopenharmony_ci if (!has_64bit) 196bf215546Sopenharmony_ci return; 197bf215546Sopenharmony_ci 198bf215546Sopenharmony_ci /* Lower 64_UINT to 32_UINT. */ 199bf215546Sopenharmony_ci unsigned new_count = 0; 200bf215546Sopenharmony_ci 201bf215546Sopenharmony_ci for (unsigned i = 0; i < count; i++) { 202bf215546Sopenharmony_ci enum pipe_format format = input[i].src_format; 203bf215546Sopenharmony_ci 204bf215546Sopenharmony_ci /* If the shader input is dvec2 or smaller, reduce the number of 205bf215546Sopenharmony_ci * components to 2 at most. If the shader input is dvec3 or larger, 206bf215546Sopenharmony_ci * expand the number of components to 3 at least. If the 3rd component 207bf215546Sopenharmony_ci * is out of bounds, the hardware shouldn't skip loading the first 208bf215546Sopenharmony_ci * 2 components. 209bf215546Sopenharmony_ci */ 210bf215546Sopenharmony_ci if (format >= PIPE_FORMAT_R64_UINT && 211bf215546Sopenharmony_ci format <= PIPE_FORMAT_R64G64B64A64_UINT) { 212bf215546Sopenharmony_ci if (input[i].dual_slot) 213bf215546Sopenharmony_ci format = MAX2(format, PIPE_FORMAT_R64G64B64_UINT); 214bf215546Sopenharmony_ci else 215bf215546Sopenharmony_ci format = MIN2(format, PIPE_FORMAT_R64G64_UINT); 216bf215546Sopenharmony_ci } 217bf215546Sopenharmony_ci 218bf215546Sopenharmony_ci switch (format) { 219bf215546Sopenharmony_ci case PIPE_FORMAT_R64_UINT: 220bf215546Sopenharmony_ci tmp[new_count] = input[i]; 221bf215546Sopenharmony_ci tmp[new_count].src_format = PIPE_FORMAT_R32G32_UINT; 222bf215546Sopenharmony_ci new_count++; 223bf215546Sopenharmony_ci break; 224bf215546Sopenharmony_ci 225bf215546Sopenharmony_ci case PIPE_FORMAT_R64G64_UINT: 226bf215546Sopenharmony_ci tmp[new_count] = input[i]; 227bf215546Sopenharmony_ci tmp[new_count].src_format = PIPE_FORMAT_R32G32B32A32_UINT; 228bf215546Sopenharmony_ci new_count++; 229bf215546Sopenharmony_ci break; 230bf215546Sopenharmony_ci 231bf215546Sopenharmony_ci case PIPE_FORMAT_R64G64B64_UINT: 232bf215546Sopenharmony_ci case PIPE_FORMAT_R64G64B64A64_UINT: 233bf215546Sopenharmony_ci assert(new_count + 2 <= PIPE_MAX_ATTRIBS); 234bf215546Sopenharmony_ci tmp[new_count] = tmp[new_count + 1] = input[i]; 235bf215546Sopenharmony_ci tmp[new_count].src_format = PIPE_FORMAT_R32G32B32A32_UINT; 236bf215546Sopenharmony_ci tmp[new_count + 1].src_format = 237bf215546Sopenharmony_ci format == PIPE_FORMAT_R64G64B64_UINT ? 238bf215546Sopenharmony_ci PIPE_FORMAT_R32G32_UINT : 239bf215546Sopenharmony_ci PIPE_FORMAT_R32G32B32A32_UINT; 240bf215546Sopenharmony_ci tmp[new_count + 1].src_offset += 16; 241bf215546Sopenharmony_ci new_count += 2; 242bf215546Sopenharmony_ci break; 243bf215546Sopenharmony_ci 244bf215546Sopenharmony_ci default: 245bf215546Sopenharmony_ci tmp[new_count++] = input[i]; 246bf215546Sopenharmony_ci break; 247bf215546Sopenharmony_ci } 248bf215546Sopenharmony_ci } 249bf215546Sopenharmony_ci 250bf215546Sopenharmony_ci *velem_count = new_count; 251bf215546Sopenharmony_ci *velems = tmp; 252bf215546Sopenharmony_ci} 253bf215546Sopenharmony_ci 254bf215546Sopenharmony_ci/* This is a helper for hardware bring-up. Don't remove. */ 255bf215546Sopenharmony_cistruct pipe_query * 256bf215546Sopenharmony_ciutil_begin_pipestat_query(struct pipe_context *ctx) 257bf215546Sopenharmony_ci{ 258bf215546Sopenharmony_ci struct pipe_query *q = 259bf215546Sopenharmony_ci ctx->create_query(ctx, PIPE_QUERY_PIPELINE_STATISTICS, 0); 260bf215546Sopenharmony_ci if (!q) 261bf215546Sopenharmony_ci return NULL; 262bf215546Sopenharmony_ci 263bf215546Sopenharmony_ci ctx->begin_query(ctx, q); 264bf215546Sopenharmony_ci return q; 265bf215546Sopenharmony_ci} 266bf215546Sopenharmony_ci 267bf215546Sopenharmony_ci/* This is a helper for hardware bring-up. Don't remove. */ 268bf215546Sopenharmony_civoid 269bf215546Sopenharmony_ciutil_end_pipestat_query(struct pipe_context *ctx, struct pipe_query *q, 270bf215546Sopenharmony_ci FILE *f) 271bf215546Sopenharmony_ci{ 272bf215546Sopenharmony_ci static unsigned counter; 273bf215546Sopenharmony_ci struct pipe_query_data_pipeline_statistics stats; 274bf215546Sopenharmony_ci 275bf215546Sopenharmony_ci ctx->end_query(ctx, q); 276bf215546Sopenharmony_ci ctx->get_query_result(ctx, q, true, (void*)&stats); 277bf215546Sopenharmony_ci ctx->destroy_query(ctx, q); 278bf215546Sopenharmony_ci 279bf215546Sopenharmony_ci fprintf(f, 280bf215546Sopenharmony_ci "Draw call %u:\n" 281bf215546Sopenharmony_ci " ia_vertices = %"PRIu64"\n" 282bf215546Sopenharmony_ci " ia_primitives = %"PRIu64"\n" 283bf215546Sopenharmony_ci " vs_invocations = %"PRIu64"\n" 284bf215546Sopenharmony_ci " gs_invocations = %"PRIu64"\n" 285bf215546Sopenharmony_ci " gs_primitives = %"PRIu64"\n" 286bf215546Sopenharmony_ci " c_invocations = %"PRIu64"\n" 287bf215546Sopenharmony_ci " c_primitives = %"PRIu64"\n" 288bf215546Sopenharmony_ci " ps_invocations = %"PRIu64"\n" 289bf215546Sopenharmony_ci " hs_invocations = %"PRIu64"\n" 290bf215546Sopenharmony_ci " ds_invocations = %"PRIu64"\n" 291bf215546Sopenharmony_ci " cs_invocations = %"PRIu64"\n", 292bf215546Sopenharmony_ci (unsigned)p_atomic_inc_return(&counter), 293bf215546Sopenharmony_ci stats.ia_vertices, 294bf215546Sopenharmony_ci stats.ia_primitives, 295bf215546Sopenharmony_ci stats.vs_invocations, 296bf215546Sopenharmony_ci stats.gs_invocations, 297bf215546Sopenharmony_ci stats.gs_primitives, 298bf215546Sopenharmony_ci stats.c_invocations, 299bf215546Sopenharmony_ci stats.c_primitives, 300bf215546Sopenharmony_ci stats.ps_invocations, 301bf215546Sopenharmony_ci stats.hs_invocations, 302bf215546Sopenharmony_ci stats.ds_invocations, 303bf215546Sopenharmony_ci stats.cs_invocations); 304bf215546Sopenharmony_ci} 305bf215546Sopenharmony_ci 306bf215546Sopenharmony_ci/* This is a helper for profiling. Don't remove. */ 307bf215546Sopenharmony_cistruct pipe_query * 308bf215546Sopenharmony_ciutil_begin_time_query(struct pipe_context *ctx) 309bf215546Sopenharmony_ci{ 310bf215546Sopenharmony_ci struct pipe_query *q = 311bf215546Sopenharmony_ci ctx->create_query(ctx, PIPE_QUERY_TIME_ELAPSED, 0); 312bf215546Sopenharmony_ci if (!q) 313bf215546Sopenharmony_ci return NULL; 314bf215546Sopenharmony_ci 315bf215546Sopenharmony_ci ctx->begin_query(ctx, q); 316bf215546Sopenharmony_ci return q; 317bf215546Sopenharmony_ci} 318bf215546Sopenharmony_ci 319bf215546Sopenharmony_ci/* This is a helper for profiling. Don't remove. */ 320bf215546Sopenharmony_civoid 321bf215546Sopenharmony_ciutil_end_time_query(struct pipe_context *ctx, struct pipe_query *q, FILE *f, 322bf215546Sopenharmony_ci const char *name) 323bf215546Sopenharmony_ci{ 324bf215546Sopenharmony_ci union pipe_query_result result; 325bf215546Sopenharmony_ci 326bf215546Sopenharmony_ci ctx->end_query(ctx, q); 327bf215546Sopenharmony_ci ctx->get_query_result(ctx, q, true, &result); 328bf215546Sopenharmony_ci ctx->destroy_query(ctx, q); 329bf215546Sopenharmony_ci 330bf215546Sopenharmony_ci fprintf(f, "Time elapsed: %s - %"PRIu64".%u us\n", name, result.u64 / 1000, (unsigned)(result.u64 % 1000) / 100); 331bf215546Sopenharmony_ci} 332bf215546Sopenharmony_ci 333bf215546Sopenharmony_ci/* This is a helper for hardware bring-up. Don't remove. */ 334bf215546Sopenharmony_civoid 335bf215546Sopenharmony_ciutil_wait_for_idle(struct pipe_context *ctx) 336bf215546Sopenharmony_ci{ 337bf215546Sopenharmony_ci struct pipe_fence_handle *fence = NULL; 338bf215546Sopenharmony_ci 339bf215546Sopenharmony_ci ctx->flush(ctx, &fence, 0); 340bf215546Sopenharmony_ci ctx->screen->fence_finish(ctx->screen, NULL, fence, PIPE_TIMEOUT_INFINITE); 341bf215546Sopenharmony_ci} 342bf215546Sopenharmony_ci 343bf215546Sopenharmony_civoid 344bf215546Sopenharmony_ciutil_throttle_init(struct util_throttle *t, uint64_t max_mem_usage) 345bf215546Sopenharmony_ci{ 346bf215546Sopenharmony_ci t->max_mem_usage = max_mem_usage; 347bf215546Sopenharmony_ci} 348bf215546Sopenharmony_ci 349bf215546Sopenharmony_civoid 350bf215546Sopenharmony_ciutil_throttle_deinit(struct pipe_screen *screen, struct util_throttle *t) 351bf215546Sopenharmony_ci{ 352bf215546Sopenharmony_ci for (unsigned i = 0; i < ARRAY_SIZE(t->ring); i++) 353bf215546Sopenharmony_ci screen->fence_reference(screen, &t->ring[i].fence, NULL); 354bf215546Sopenharmony_ci} 355bf215546Sopenharmony_ci 356bf215546Sopenharmony_cistatic uint64_t 357bf215546Sopenharmony_ciutil_get_throttle_total_memory_usage(struct util_throttle *t) 358bf215546Sopenharmony_ci{ 359bf215546Sopenharmony_ci uint64_t total_usage = 0; 360bf215546Sopenharmony_ci 361bf215546Sopenharmony_ci for (unsigned i = 0; i < ARRAY_SIZE(t->ring); i++) 362bf215546Sopenharmony_ci total_usage += t->ring[i].mem_usage; 363bf215546Sopenharmony_ci return total_usage; 364bf215546Sopenharmony_ci} 365bf215546Sopenharmony_ci 366bf215546Sopenharmony_cistatic void util_dump_throttle_ring(struct util_throttle *t) 367bf215546Sopenharmony_ci{ 368bf215546Sopenharmony_ci printf("Throttle:\n"); 369bf215546Sopenharmony_ci for (unsigned i = 0; i < ARRAY_SIZE(t->ring); i++) { 370bf215546Sopenharmony_ci printf(" ring[%u]: fence = %s, mem_usage = %"PRIu64"%s%s\n", 371bf215546Sopenharmony_ci i, t->ring[i].fence ? "yes" : " no", 372bf215546Sopenharmony_ci t->ring[i].mem_usage, 373bf215546Sopenharmony_ci t->flush_index == i ? " [flush]" : "", 374bf215546Sopenharmony_ci t->wait_index == i ? " [wait]" : ""); 375bf215546Sopenharmony_ci } 376bf215546Sopenharmony_ci} 377bf215546Sopenharmony_ci 378bf215546Sopenharmony_ci/** 379bf215546Sopenharmony_ci * Notify util_throttle that the next operation allocates memory. 380bf215546Sopenharmony_ci * util_throttle tracks memory usage and waits for fences until its tracked 381bf215546Sopenharmony_ci * memory usage decreases. 382bf215546Sopenharmony_ci * 383bf215546Sopenharmony_ci * Example: 384bf215546Sopenharmony_ci * util_throttle_memory_usage(..., w*h*d*Bpp); 385bf215546Sopenharmony_ci * TexSubImage(..., w, h, d, ...); 386bf215546Sopenharmony_ci * 387bf215546Sopenharmony_ci * This means that TexSubImage can't allocate more memory its maximum limit 388bf215546Sopenharmony_ci * set during initialization. 389bf215546Sopenharmony_ci */ 390bf215546Sopenharmony_civoid 391bf215546Sopenharmony_ciutil_throttle_memory_usage(struct pipe_context *pipe, 392bf215546Sopenharmony_ci struct util_throttle *t, uint64_t memory_size) 393bf215546Sopenharmony_ci{ 394bf215546Sopenharmony_ci (void)util_dump_throttle_ring; /* silence warning */ 395bf215546Sopenharmony_ci 396bf215546Sopenharmony_ci if (!t->max_mem_usage) 397bf215546Sopenharmony_ci return; 398bf215546Sopenharmony_ci 399bf215546Sopenharmony_ci struct pipe_screen *screen = pipe->screen; 400bf215546Sopenharmony_ci struct pipe_fence_handle **fence = NULL; 401bf215546Sopenharmony_ci unsigned ring_size = ARRAY_SIZE(t->ring); 402bf215546Sopenharmony_ci uint64_t total = util_get_throttle_total_memory_usage(t); 403bf215546Sopenharmony_ci 404bf215546Sopenharmony_ci /* If there is not enough memory, walk the list of fences and find 405bf215546Sopenharmony_ci * the latest one that we need to wait for. 406bf215546Sopenharmony_ci */ 407bf215546Sopenharmony_ci while (t->wait_index != t->flush_index && 408bf215546Sopenharmony_ci total && total + memory_size > t->max_mem_usage) { 409bf215546Sopenharmony_ci assert(t->ring[t->wait_index].fence); 410bf215546Sopenharmony_ci 411bf215546Sopenharmony_ci /* Release an older fence if we need to wait for a newer one. */ 412bf215546Sopenharmony_ci if (fence) 413bf215546Sopenharmony_ci screen->fence_reference(screen, fence, NULL); 414bf215546Sopenharmony_ci 415bf215546Sopenharmony_ci fence = &t->ring[t->wait_index].fence; 416bf215546Sopenharmony_ci t->ring[t->wait_index].mem_usage = 0; 417bf215546Sopenharmony_ci t->wait_index = (t->wait_index + 1) % ring_size; 418bf215546Sopenharmony_ci 419bf215546Sopenharmony_ci total = util_get_throttle_total_memory_usage(t); 420bf215546Sopenharmony_ci } 421bf215546Sopenharmony_ci 422bf215546Sopenharmony_ci /* Wait for the fence to decrease memory usage. */ 423bf215546Sopenharmony_ci if (fence) { 424bf215546Sopenharmony_ci screen->fence_finish(screen, pipe, *fence, PIPE_TIMEOUT_INFINITE); 425bf215546Sopenharmony_ci screen->fence_reference(screen, fence, NULL); 426bf215546Sopenharmony_ci } 427bf215546Sopenharmony_ci 428bf215546Sopenharmony_ci /* Flush and get a fence if we've exhausted memory usage for the current 429bf215546Sopenharmony_ci * slot. 430bf215546Sopenharmony_ci */ 431bf215546Sopenharmony_ci if (t->ring[t->flush_index].mem_usage && 432bf215546Sopenharmony_ci t->ring[t->flush_index].mem_usage + memory_size > 433bf215546Sopenharmony_ci t->max_mem_usage / (ring_size / 2)) { 434bf215546Sopenharmony_ci struct pipe_fence_handle **fence = 435bf215546Sopenharmony_ci &t->ring[t->flush_index].fence; 436bf215546Sopenharmony_ci 437bf215546Sopenharmony_ci /* Expect that the current flush slot doesn't have a fence yet. */ 438bf215546Sopenharmony_ci assert(!*fence); 439bf215546Sopenharmony_ci 440bf215546Sopenharmony_ci pipe->flush(pipe, fence, PIPE_FLUSH_ASYNC); 441bf215546Sopenharmony_ci t->flush_index = (t->flush_index + 1) % ring_size; 442bf215546Sopenharmony_ci 443bf215546Sopenharmony_ci /* Vacate the next slot if it's occupied. This should be rare. */ 444bf215546Sopenharmony_ci if (t->flush_index == t->wait_index) { 445bf215546Sopenharmony_ci struct pipe_fence_handle **fence = 446bf215546Sopenharmony_ci &t->ring[t->wait_index].fence; 447bf215546Sopenharmony_ci 448bf215546Sopenharmony_ci t->ring[t->wait_index].mem_usage = 0; 449bf215546Sopenharmony_ci t->wait_index = (t->wait_index + 1) % ring_size; 450bf215546Sopenharmony_ci 451bf215546Sopenharmony_ci assert(*fence); 452bf215546Sopenharmony_ci screen->fence_finish(screen, pipe, *fence, PIPE_TIMEOUT_INFINITE); 453bf215546Sopenharmony_ci screen->fence_reference(screen, fence, NULL); 454bf215546Sopenharmony_ci } 455bf215546Sopenharmony_ci 456bf215546Sopenharmony_ci assert(!t->ring[t->flush_index].mem_usage); 457bf215546Sopenharmony_ci assert(!t->ring[t->flush_index].fence); 458bf215546Sopenharmony_ci } 459bf215546Sopenharmony_ci 460bf215546Sopenharmony_ci t->ring[t->flush_index].mem_usage += memory_size; 461bf215546Sopenharmony_ci} 462bf215546Sopenharmony_ci 463bf215546Sopenharmony_cibool 464bf215546Sopenharmony_ciutil_lower_clearsize_to_dword(const void *clearValue, int *clearValueSize, uint32_t *clamped) 465bf215546Sopenharmony_ci{ 466bf215546Sopenharmony_ci /* Reduce a large clear value size if possible. */ 467bf215546Sopenharmony_ci if (*clearValueSize > 4) { 468bf215546Sopenharmony_ci bool clear_dword_duplicated = true; 469bf215546Sopenharmony_ci const uint32_t *clear_value = clearValue; 470bf215546Sopenharmony_ci 471bf215546Sopenharmony_ci /* See if we can lower large fills to dword fills. */ 472bf215546Sopenharmony_ci for (unsigned i = 1; i < *clearValueSize / 4; i++) { 473bf215546Sopenharmony_ci if (clear_value[0] != clear_value[i]) { 474bf215546Sopenharmony_ci clear_dword_duplicated = false; 475bf215546Sopenharmony_ci break; 476bf215546Sopenharmony_ci } 477bf215546Sopenharmony_ci } 478bf215546Sopenharmony_ci if (clear_dword_duplicated) { 479bf215546Sopenharmony_ci *clamped = *clear_value; 480bf215546Sopenharmony_ci *clearValueSize = 4; 481bf215546Sopenharmony_ci } 482bf215546Sopenharmony_ci return clear_dword_duplicated; 483bf215546Sopenharmony_ci } 484bf215546Sopenharmony_ci 485bf215546Sopenharmony_ci /* Expand a small clear value size. */ 486bf215546Sopenharmony_ci if (*clearValueSize <= 2) { 487bf215546Sopenharmony_ci if (*clearValueSize == 1) { 488bf215546Sopenharmony_ci *clamped = *(uint8_t *)clearValue; 489bf215546Sopenharmony_ci *clamped |= 490bf215546Sopenharmony_ci (*clamped << 8) | (*clamped << 16) | (*clamped << 24); 491bf215546Sopenharmony_ci } else { 492bf215546Sopenharmony_ci *clamped = *(uint16_t *)clearValue; 493bf215546Sopenharmony_ci *clamped |= *clamped << 16; 494bf215546Sopenharmony_ci } 495bf215546Sopenharmony_ci *clearValueSize = 4; 496bf215546Sopenharmony_ci return true; 497bf215546Sopenharmony_ci } 498bf215546Sopenharmony_ci return false; 499bf215546Sopenharmony_ci} 500bf215546Sopenharmony_ci 501bf215546Sopenharmony_civoid 502bf215546Sopenharmony_ciutil_init_pipe_vertex_state(struct pipe_screen *screen, 503bf215546Sopenharmony_ci struct pipe_vertex_buffer *buffer, 504bf215546Sopenharmony_ci const struct pipe_vertex_element *elements, 505bf215546Sopenharmony_ci unsigned num_elements, 506bf215546Sopenharmony_ci struct pipe_resource *indexbuf, 507bf215546Sopenharmony_ci uint32_t full_velem_mask, 508bf215546Sopenharmony_ci struct pipe_vertex_state *state) 509bf215546Sopenharmony_ci{ 510bf215546Sopenharmony_ci assert(num_elements == util_bitcount(full_velem_mask)); 511bf215546Sopenharmony_ci 512bf215546Sopenharmony_ci pipe_reference_init(&state->reference, 1); 513bf215546Sopenharmony_ci state->screen = screen; 514bf215546Sopenharmony_ci 515bf215546Sopenharmony_ci pipe_vertex_buffer_reference(&state->input.vbuffer, buffer); 516bf215546Sopenharmony_ci pipe_resource_reference(&state->input.indexbuf, indexbuf); 517bf215546Sopenharmony_ci state->input.num_elements = num_elements; 518bf215546Sopenharmony_ci for (unsigned i = 0; i < num_elements; i++) 519bf215546Sopenharmony_ci state->input.elements[i] = elements[i]; 520bf215546Sopenharmony_ci state->input.full_velem_mask = full_velem_mask; 521bf215546Sopenharmony_ci} 522bf215546Sopenharmony_ci 523bf215546Sopenharmony_ci/** 524bf215546Sopenharmony_ci * Clamp color value to format range. 525bf215546Sopenharmony_ci */ 526bf215546Sopenharmony_ciunion pipe_color_union 527bf215546Sopenharmony_ciutil_clamp_color(enum pipe_format format, 528bf215546Sopenharmony_ci const union pipe_color_union *color) 529bf215546Sopenharmony_ci{ 530bf215546Sopenharmony_ci union pipe_color_union clamp_color = *color; 531bf215546Sopenharmony_ci int i; 532bf215546Sopenharmony_ci 533bf215546Sopenharmony_ci for (i = 0; i < util_format_get_nr_components(format); i++) { 534bf215546Sopenharmony_ci uint8_t bits = util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, i); 535bf215546Sopenharmony_ci 536bf215546Sopenharmony_ci if (util_format_is_unorm(format)) 537bf215546Sopenharmony_ci clamp_color.ui[i] = _mesa_unorm_to_unorm(clamp_color.ui[i], bits, bits); 538bf215546Sopenharmony_ci else if (util_format_is_snorm(format)) 539bf215546Sopenharmony_ci clamp_color.i[i] = _mesa_snorm_to_snorm(clamp_color.i[i], bits, bits); 540bf215546Sopenharmony_ci else if (util_format_is_pure_uint(format)) 541bf215546Sopenharmony_ci clamp_color.ui[i] = _mesa_unsigned_to_unsigned(clamp_color.ui[i], bits); 542bf215546Sopenharmony_ci else if (util_format_is_pure_sint(format)) 543bf215546Sopenharmony_ci clamp_color.i[i] = _mesa_signed_to_signed(clamp_color.i[i], bits); 544bf215546Sopenharmony_ci } 545bf215546Sopenharmony_ci 546bf215546Sopenharmony_ci return clamp_color; 547bf215546Sopenharmony_ci} 548