1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2012 Intel Corporation 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 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21bf215546Sopenharmony_ci * IN THE SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci#include "main/glthread_marshal.h" 25bf215546Sopenharmony_ci#include "main/dispatch.h" 26bf215546Sopenharmony_ci#include "main/bufferobj.h" 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci/** 29bf215546Sopenharmony_ci * Create an upload buffer. This is called from the app thread, so everything 30bf215546Sopenharmony_ci * has to be thread-safe in the driver. 31bf215546Sopenharmony_ci */ 32bf215546Sopenharmony_cistatic struct gl_buffer_object * 33bf215546Sopenharmony_cinew_upload_buffer(struct gl_context *ctx, GLsizeiptr size, uint8_t **ptr) 34bf215546Sopenharmony_ci{ 35bf215546Sopenharmony_ci assert(ctx->GLThread.SupportsBufferUploads); 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_ci struct gl_buffer_object *obj = 38bf215546Sopenharmony_ci _mesa_bufferobj_alloc(ctx, -1); 39bf215546Sopenharmony_ci if (!obj) 40bf215546Sopenharmony_ci return NULL; 41bf215546Sopenharmony_ci 42bf215546Sopenharmony_ci obj->Immutable = true; 43bf215546Sopenharmony_ci 44bf215546Sopenharmony_ci if (!_mesa_bufferobj_data(ctx, GL_ARRAY_BUFFER, size, NULL, 45bf215546Sopenharmony_ci GL_WRITE_ONLY, 46bf215546Sopenharmony_ci GL_CLIENT_STORAGE_BIT | GL_MAP_WRITE_BIT, 47bf215546Sopenharmony_ci obj)) { 48bf215546Sopenharmony_ci _mesa_delete_buffer_object(ctx, obj); 49bf215546Sopenharmony_ci return NULL; 50bf215546Sopenharmony_ci } 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_ci *ptr = _mesa_bufferobj_map_range(ctx, 0, size, 53bf215546Sopenharmony_ci GL_MAP_WRITE_BIT | 54bf215546Sopenharmony_ci GL_MAP_UNSYNCHRONIZED_BIT | 55bf215546Sopenharmony_ci MESA_MAP_THREAD_SAFE_BIT, 56bf215546Sopenharmony_ci obj, MAP_GLTHREAD); 57bf215546Sopenharmony_ci if (!*ptr) { 58bf215546Sopenharmony_ci _mesa_delete_buffer_object(ctx, obj); 59bf215546Sopenharmony_ci return NULL; 60bf215546Sopenharmony_ci } 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_ci return obj; 63bf215546Sopenharmony_ci} 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_civoid 66bf215546Sopenharmony_ci_mesa_glthread_upload(struct gl_context *ctx, const void *data, 67bf215546Sopenharmony_ci GLsizeiptr size, unsigned *out_offset, 68bf215546Sopenharmony_ci struct gl_buffer_object **out_buffer, 69bf215546Sopenharmony_ci uint8_t **out_ptr) 70bf215546Sopenharmony_ci{ 71bf215546Sopenharmony_ci struct glthread_state *glthread = &ctx->GLThread; 72bf215546Sopenharmony_ci const unsigned default_size = 1024 * 1024; 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_ci if (unlikely(size > INT_MAX)) 75bf215546Sopenharmony_ci return; 76bf215546Sopenharmony_ci 77bf215546Sopenharmony_ci /* The alignment was chosen arbitrarily. */ 78bf215546Sopenharmony_ci unsigned offset = align(glthread->upload_offset, 8); 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_ci /* Allocate a new buffer if needed. */ 81bf215546Sopenharmony_ci if (unlikely(!glthread->upload_buffer || offset + size > default_size)) { 82bf215546Sopenharmony_ci /* If the size is greater than the buffer size, allocate a separate buffer 83bf215546Sopenharmony_ci * just for this upload. 84bf215546Sopenharmony_ci */ 85bf215546Sopenharmony_ci if (unlikely(size > default_size)) { 86bf215546Sopenharmony_ci uint8_t *ptr; 87bf215546Sopenharmony_ci 88bf215546Sopenharmony_ci assert(*out_buffer == NULL); 89bf215546Sopenharmony_ci *out_buffer = new_upload_buffer(ctx, size, &ptr); 90bf215546Sopenharmony_ci if (!*out_buffer) 91bf215546Sopenharmony_ci return; 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_ci *out_offset = 0; 94bf215546Sopenharmony_ci if (data) 95bf215546Sopenharmony_ci memcpy(ptr, data, size); 96bf215546Sopenharmony_ci else 97bf215546Sopenharmony_ci *out_ptr = ptr; 98bf215546Sopenharmony_ci return; 99bf215546Sopenharmony_ci } 100bf215546Sopenharmony_ci 101bf215546Sopenharmony_ci if (glthread->upload_buffer_private_refcount > 0) { 102bf215546Sopenharmony_ci p_atomic_add(&glthread->upload_buffer->RefCount, 103bf215546Sopenharmony_ci -glthread->upload_buffer_private_refcount); 104bf215546Sopenharmony_ci glthread->upload_buffer_private_refcount = 0; 105bf215546Sopenharmony_ci } 106bf215546Sopenharmony_ci _mesa_reference_buffer_object(ctx, &glthread->upload_buffer, NULL); 107bf215546Sopenharmony_ci glthread->upload_buffer = 108bf215546Sopenharmony_ci new_upload_buffer(ctx, default_size, &glthread->upload_ptr); 109bf215546Sopenharmony_ci glthread->upload_offset = 0; 110bf215546Sopenharmony_ci offset = 0; 111bf215546Sopenharmony_ci 112bf215546Sopenharmony_ci /* Since atomic operations are very very slow when 2 threads are not 113bf215546Sopenharmony_ci * sharing one L3 cache (which can happen on AMD Zen), prevent using 114bf215546Sopenharmony_ci * atomics as follows: 115bf215546Sopenharmony_ci * 116bf215546Sopenharmony_ci * This function has to return a buffer reference to the caller. 117bf215546Sopenharmony_ci * Instead of atomic_inc for every call, it does all possible future 118bf215546Sopenharmony_ci * increments in advance when the upload buffer is allocated. 119bf215546Sopenharmony_ci * The maximum number of times the function can be called per upload 120bf215546Sopenharmony_ci * buffer is default_size, because the minimum allocation size is 1. 121bf215546Sopenharmony_ci * Therefore the function can only return default_size number of 122bf215546Sopenharmony_ci * references at most, so we will never need more. This is the number 123bf215546Sopenharmony_ci * that is added to RefCount at allocation. 124bf215546Sopenharmony_ci * 125bf215546Sopenharmony_ci * upload_buffer_private_refcount tracks how many buffer references 126bf215546Sopenharmony_ci * are left to return to callers. If the buffer is full and there are 127bf215546Sopenharmony_ci * still references left, they are atomically subtracted from RefCount 128bf215546Sopenharmony_ci * before the buffer is unreferenced. 129bf215546Sopenharmony_ci * 130bf215546Sopenharmony_ci * This can increase performance by 20%. 131bf215546Sopenharmony_ci */ 132bf215546Sopenharmony_ci glthread->upload_buffer->RefCount += default_size; 133bf215546Sopenharmony_ci glthread->upload_buffer_private_refcount = default_size; 134bf215546Sopenharmony_ci } 135bf215546Sopenharmony_ci 136bf215546Sopenharmony_ci /* Upload data. */ 137bf215546Sopenharmony_ci if (data) 138bf215546Sopenharmony_ci memcpy(glthread->upload_ptr + offset, data, size); 139bf215546Sopenharmony_ci else 140bf215546Sopenharmony_ci *out_ptr = glthread->upload_ptr + offset; 141bf215546Sopenharmony_ci 142bf215546Sopenharmony_ci glthread->upload_offset = offset + size; 143bf215546Sopenharmony_ci *out_offset = offset; 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_ci assert(*out_buffer == NULL); 146bf215546Sopenharmony_ci assert(glthread->upload_buffer_private_refcount > 0); 147bf215546Sopenharmony_ci *out_buffer = glthread->upload_buffer; 148bf215546Sopenharmony_ci glthread->upload_buffer_private_refcount--; 149bf215546Sopenharmony_ci} 150bf215546Sopenharmony_ci 151bf215546Sopenharmony_ci/** Tracks the current bindings for the vertex array and index array buffers. 152bf215546Sopenharmony_ci * 153bf215546Sopenharmony_ci * This is part of what we need to enable glthread on compat-GL contexts that 154bf215546Sopenharmony_ci * happen to use VBOs, without also supporting the full tracking of VBO vs 155bf215546Sopenharmony_ci * user vertex array bindings per attribute on each vertex array for 156bf215546Sopenharmony_ci * determining what to upload at draw call time. 157bf215546Sopenharmony_ci * 158bf215546Sopenharmony_ci * Note that GL core makes it so that a buffer binding with an invalid handle 159bf215546Sopenharmony_ci * in the "buffer" parameter will throw an error, and then a 160bf215546Sopenharmony_ci * glVertexAttribPointer() that followsmight not end up pointing at a VBO. 161bf215546Sopenharmony_ci * However, in GL core the draw call would throw an error as well, so we don't 162bf215546Sopenharmony_ci * really care if our tracking is wrong for this case -- we never need to 163bf215546Sopenharmony_ci * marshal user data for draw calls, and the unmarshal will just generate an 164bf215546Sopenharmony_ci * error or not as appropriate. 165bf215546Sopenharmony_ci * 166bf215546Sopenharmony_ci * For compatibility GL, we do need to accurately know whether the draw call 167bf215546Sopenharmony_ci * on the unmarshal side will dereference a user pointer or load data from a 168bf215546Sopenharmony_ci * VBO per vertex. That would make it seem like we need to track whether a 169bf215546Sopenharmony_ci * "buffer" is valid, so that we can know when an error will be generated 170bf215546Sopenharmony_ci * instead of updating the binding. However, compat GL has the ridiculous 171bf215546Sopenharmony_ci * feature that if you pass a bad name, it just gens a buffer object for you, 172bf215546Sopenharmony_ci * so we escape without having to know if things are valid or not. 173bf215546Sopenharmony_ci */ 174bf215546Sopenharmony_civoid 175bf215546Sopenharmony_ci_mesa_glthread_BindBuffer(struct gl_context *ctx, GLenum target, GLuint buffer) 176bf215546Sopenharmony_ci{ 177bf215546Sopenharmony_ci struct glthread_state *glthread = &ctx->GLThread; 178bf215546Sopenharmony_ci 179bf215546Sopenharmony_ci switch (target) { 180bf215546Sopenharmony_ci case GL_ARRAY_BUFFER: 181bf215546Sopenharmony_ci glthread->CurrentArrayBufferName = buffer; 182bf215546Sopenharmony_ci break; 183bf215546Sopenharmony_ci case GL_ELEMENT_ARRAY_BUFFER: 184bf215546Sopenharmony_ci /* The current element array buffer binding is actually tracked in the 185bf215546Sopenharmony_ci * vertex array object instead of the context, so this would need to 186bf215546Sopenharmony_ci * change on vertex array object updates. 187bf215546Sopenharmony_ci */ 188bf215546Sopenharmony_ci glthread->CurrentVAO->CurrentElementBufferName = buffer; 189bf215546Sopenharmony_ci break; 190bf215546Sopenharmony_ci case GL_DRAW_INDIRECT_BUFFER: 191bf215546Sopenharmony_ci glthread->CurrentDrawIndirectBufferName = buffer; 192bf215546Sopenharmony_ci break; 193bf215546Sopenharmony_ci case GL_PIXEL_PACK_BUFFER: 194bf215546Sopenharmony_ci glthread->CurrentPixelPackBufferName = buffer; 195bf215546Sopenharmony_ci break; 196bf215546Sopenharmony_ci case GL_PIXEL_UNPACK_BUFFER: 197bf215546Sopenharmony_ci glthread->CurrentPixelUnpackBufferName = buffer; 198bf215546Sopenharmony_ci break; 199bf215546Sopenharmony_ci case GL_QUERY_BUFFER: 200bf215546Sopenharmony_ci glthread->CurrentQueryBufferName = buffer; 201bf215546Sopenharmony_ci break; 202bf215546Sopenharmony_ci } 203bf215546Sopenharmony_ci} 204bf215546Sopenharmony_ci 205bf215546Sopenharmony_civoid 206bf215546Sopenharmony_ci_mesa_glthread_DeleteBuffers(struct gl_context *ctx, GLsizei n, 207bf215546Sopenharmony_ci const GLuint *buffers) 208bf215546Sopenharmony_ci{ 209bf215546Sopenharmony_ci struct glthread_state *glthread = &ctx->GLThread; 210bf215546Sopenharmony_ci 211bf215546Sopenharmony_ci if (!buffers || n < 0) 212bf215546Sopenharmony_ci return; 213bf215546Sopenharmony_ci 214bf215546Sopenharmony_ci for (unsigned i = 0; i < n; i++) { 215bf215546Sopenharmony_ci GLuint id = buffers[i]; 216bf215546Sopenharmony_ci 217bf215546Sopenharmony_ci if (id == glthread->CurrentArrayBufferName) 218bf215546Sopenharmony_ci _mesa_glthread_BindBuffer(ctx, GL_ARRAY_BUFFER, 0); 219bf215546Sopenharmony_ci if (id == glthread->CurrentVAO->CurrentElementBufferName) 220bf215546Sopenharmony_ci _mesa_glthread_BindBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, 0); 221bf215546Sopenharmony_ci if (id == glthread->CurrentDrawIndirectBufferName) 222bf215546Sopenharmony_ci _mesa_glthread_BindBuffer(ctx, GL_DRAW_INDIRECT_BUFFER, 0); 223bf215546Sopenharmony_ci if (id == glthread->CurrentPixelPackBufferName) 224bf215546Sopenharmony_ci _mesa_glthread_BindBuffer(ctx, GL_PIXEL_PACK_BUFFER, 0); 225bf215546Sopenharmony_ci if (id == glthread->CurrentPixelUnpackBufferName) 226bf215546Sopenharmony_ci _mesa_glthread_BindBuffer(ctx, GL_PIXEL_UNPACK_BUFFER, 0); 227bf215546Sopenharmony_ci } 228bf215546Sopenharmony_ci} 229bf215546Sopenharmony_ci 230bf215546Sopenharmony_ci/* BufferData: marshalled asynchronously */ 231bf215546Sopenharmony_cistruct marshal_cmd_BufferData 232bf215546Sopenharmony_ci{ 233bf215546Sopenharmony_ci struct marshal_cmd_base cmd_base; 234bf215546Sopenharmony_ci GLuint target_or_name; 235bf215546Sopenharmony_ci GLsizeiptr size; 236bf215546Sopenharmony_ci GLenum usage; 237bf215546Sopenharmony_ci const GLvoid *data_external_mem; 238bf215546Sopenharmony_ci bool data_null; /* If set, no data follows for "data" */ 239bf215546Sopenharmony_ci bool named; 240bf215546Sopenharmony_ci bool ext_dsa; 241bf215546Sopenharmony_ci /* Next size bytes are GLubyte data[size] */ 242bf215546Sopenharmony_ci}; 243bf215546Sopenharmony_ci 244bf215546Sopenharmony_ciuint32_t 245bf215546Sopenharmony_ci_mesa_unmarshal_BufferData(struct gl_context *ctx, 246bf215546Sopenharmony_ci const struct marshal_cmd_BufferData *cmd, 247bf215546Sopenharmony_ci const uint64_t *last) 248bf215546Sopenharmony_ci{ 249bf215546Sopenharmony_ci const GLuint target_or_name = cmd->target_or_name; 250bf215546Sopenharmony_ci const GLsizei size = cmd->size; 251bf215546Sopenharmony_ci const GLenum usage = cmd->usage; 252bf215546Sopenharmony_ci const void *data; 253bf215546Sopenharmony_ci 254bf215546Sopenharmony_ci if (cmd->data_null) 255bf215546Sopenharmony_ci data = NULL; 256bf215546Sopenharmony_ci else if (!cmd->named && target_or_name == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD) 257bf215546Sopenharmony_ci data = cmd->data_external_mem; 258bf215546Sopenharmony_ci else 259bf215546Sopenharmony_ci data = (const void *) (cmd + 1); 260bf215546Sopenharmony_ci 261bf215546Sopenharmony_ci if (cmd->ext_dsa) { 262bf215546Sopenharmony_ci CALL_NamedBufferDataEXT(ctx->CurrentServerDispatch, 263bf215546Sopenharmony_ci (target_or_name, size, data, usage)); 264bf215546Sopenharmony_ci } else if (cmd->named) { 265bf215546Sopenharmony_ci CALL_NamedBufferData(ctx->CurrentServerDispatch, 266bf215546Sopenharmony_ci (target_or_name, size, data, usage)); 267bf215546Sopenharmony_ci } else { 268bf215546Sopenharmony_ci CALL_BufferData(ctx->CurrentServerDispatch, 269bf215546Sopenharmony_ci (target_or_name, size, data, usage)); 270bf215546Sopenharmony_ci } 271bf215546Sopenharmony_ci return cmd->cmd_base.cmd_size; 272bf215546Sopenharmony_ci} 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ciuint32_t 275bf215546Sopenharmony_ci_mesa_unmarshal_NamedBufferData(struct gl_context *ctx, 276bf215546Sopenharmony_ci const struct marshal_cmd_NamedBufferData *cmd, 277bf215546Sopenharmony_ci const uint64_t *last) 278bf215546Sopenharmony_ci{ 279bf215546Sopenharmony_ci unreachable("never used - all BufferData variants use DISPATCH_CMD_BufferData"); 280bf215546Sopenharmony_ci return 0; 281bf215546Sopenharmony_ci} 282bf215546Sopenharmony_ci 283bf215546Sopenharmony_ciuint32_t 284bf215546Sopenharmony_ci_mesa_unmarshal_NamedBufferDataEXT(struct gl_context *ctx, 285bf215546Sopenharmony_ci const struct marshal_cmd_NamedBufferDataEXT *cmd, 286bf215546Sopenharmony_ci const uint64_t *last) 287bf215546Sopenharmony_ci{ 288bf215546Sopenharmony_ci unreachable("never used - all BufferData variants use DISPATCH_CMD_BufferData"); 289bf215546Sopenharmony_ci return 0; 290bf215546Sopenharmony_ci} 291bf215546Sopenharmony_ci 292bf215546Sopenharmony_cistatic void 293bf215546Sopenharmony_ci_mesa_marshal_BufferData_merged(GLuint target_or_name, GLsizeiptr size, 294bf215546Sopenharmony_ci const GLvoid *data, GLenum usage, bool named, 295bf215546Sopenharmony_ci bool ext_dsa, const char *func) 296bf215546Sopenharmony_ci{ 297bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 298bf215546Sopenharmony_ci bool external_mem = !named && 299bf215546Sopenharmony_ci target_or_name == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD; 300bf215546Sopenharmony_ci bool copy_data = data && !external_mem; 301bf215546Sopenharmony_ci size_t cmd_size = sizeof(struct marshal_cmd_BufferData) + (copy_data ? size : 0); 302bf215546Sopenharmony_ci 303bf215546Sopenharmony_ci if (unlikely(size < 0 || size > INT_MAX || cmd_size > MARSHAL_MAX_CMD_SIZE || 304bf215546Sopenharmony_ci (named && target_or_name == 0))) { 305bf215546Sopenharmony_ci _mesa_glthread_finish_before(ctx, func); 306bf215546Sopenharmony_ci if (named) { 307bf215546Sopenharmony_ci CALL_NamedBufferData(ctx->CurrentServerDispatch, 308bf215546Sopenharmony_ci (target_or_name, size, data, usage)); 309bf215546Sopenharmony_ci } else { 310bf215546Sopenharmony_ci CALL_BufferData(ctx->CurrentServerDispatch, 311bf215546Sopenharmony_ci (target_or_name, size, data, usage)); 312bf215546Sopenharmony_ci } 313bf215546Sopenharmony_ci return; 314bf215546Sopenharmony_ci } 315bf215546Sopenharmony_ci 316bf215546Sopenharmony_ci struct marshal_cmd_BufferData *cmd = 317bf215546Sopenharmony_ci _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_BufferData, 318bf215546Sopenharmony_ci cmd_size); 319bf215546Sopenharmony_ci 320bf215546Sopenharmony_ci cmd->target_or_name = target_or_name; 321bf215546Sopenharmony_ci cmd->size = size; 322bf215546Sopenharmony_ci cmd->usage = usage; 323bf215546Sopenharmony_ci cmd->data_null = !data; 324bf215546Sopenharmony_ci cmd->named = named; 325bf215546Sopenharmony_ci cmd->ext_dsa = ext_dsa; 326bf215546Sopenharmony_ci cmd->data_external_mem = data; 327bf215546Sopenharmony_ci 328bf215546Sopenharmony_ci if (copy_data) { 329bf215546Sopenharmony_ci char *variable_data = (char *) (cmd + 1); 330bf215546Sopenharmony_ci memcpy(variable_data, data, size); 331bf215546Sopenharmony_ci } 332bf215546Sopenharmony_ci} 333bf215546Sopenharmony_ci 334bf215546Sopenharmony_civoid GLAPIENTRY 335bf215546Sopenharmony_ci_mesa_marshal_BufferData(GLenum target, GLsizeiptr size, const GLvoid * data, 336bf215546Sopenharmony_ci GLenum usage) 337bf215546Sopenharmony_ci{ 338bf215546Sopenharmony_ci _mesa_marshal_BufferData_merged(target, size, data, usage, false, false, 339bf215546Sopenharmony_ci "BufferData"); 340bf215546Sopenharmony_ci} 341bf215546Sopenharmony_ci 342bf215546Sopenharmony_civoid GLAPIENTRY 343bf215546Sopenharmony_ci_mesa_marshal_NamedBufferData(GLuint buffer, GLsizeiptr size, 344bf215546Sopenharmony_ci const GLvoid * data, GLenum usage) 345bf215546Sopenharmony_ci{ 346bf215546Sopenharmony_ci _mesa_marshal_BufferData_merged(buffer, size, data, usage, true, false, 347bf215546Sopenharmony_ci "NamedBufferData"); 348bf215546Sopenharmony_ci} 349bf215546Sopenharmony_ci 350bf215546Sopenharmony_civoid GLAPIENTRY 351bf215546Sopenharmony_ci_mesa_marshal_NamedBufferDataEXT(GLuint buffer, GLsizeiptr size, 352bf215546Sopenharmony_ci const GLvoid *data, GLenum usage) 353bf215546Sopenharmony_ci{ 354bf215546Sopenharmony_ci _mesa_marshal_BufferData_merged(buffer, size, data, usage, true, true, 355bf215546Sopenharmony_ci "NamedBufferDataEXT"); 356bf215546Sopenharmony_ci} 357bf215546Sopenharmony_ci 358bf215546Sopenharmony_ci 359bf215546Sopenharmony_ci/* BufferSubData: marshalled asynchronously */ 360bf215546Sopenharmony_cistruct marshal_cmd_BufferSubData 361bf215546Sopenharmony_ci{ 362bf215546Sopenharmony_ci struct marshal_cmd_base cmd_base; 363bf215546Sopenharmony_ci GLenum target_or_name; 364bf215546Sopenharmony_ci GLintptr offset; 365bf215546Sopenharmony_ci GLsizeiptr size; 366bf215546Sopenharmony_ci bool named; 367bf215546Sopenharmony_ci bool ext_dsa; 368bf215546Sopenharmony_ci /* Next size bytes are GLubyte data[size] */ 369bf215546Sopenharmony_ci}; 370bf215546Sopenharmony_ci 371bf215546Sopenharmony_ciuint32_t 372bf215546Sopenharmony_ci_mesa_unmarshal_BufferSubData(struct gl_context *ctx, 373bf215546Sopenharmony_ci const struct marshal_cmd_BufferSubData *cmd, 374bf215546Sopenharmony_ci const uint64_t *last) 375bf215546Sopenharmony_ci{ 376bf215546Sopenharmony_ci const GLenum target_or_name = cmd->target_or_name; 377bf215546Sopenharmony_ci const GLintptr offset = cmd->offset; 378bf215546Sopenharmony_ci const GLsizeiptr size = cmd->size; 379bf215546Sopenharmony_ci const void *data = (const void *) (cmd + 1); 380bf215546Sopenharmony_ci 381bf215546Sopenharmony_ci if (cmd->ext_dsa) { 382bf215546Sopenharmony_ci CALL_NamedBufferSubDataEXT(ctx->CurrentServerDispatch, 383bf215546Sopenharmony_ci (target_or_name, offset, size, data)); 384bf215546Sopenharmony_ci } else if (cmd->named) { 385bf215546Sopenharmony_ci CALL_NamedBufferSubData(ctx->CurrentServerDispatch, 386bf215546Sopenharmony_ci (target_or_name, offset, size, data)); 387bf215546Sopenharmony_ci } else { 388bf215546Sopenharmony_ci CALL_BufferSubData(ctx->CurrentServerDispatch, 389bf215546Sopenharmony_ci (target_or_name, offset, size, data)); 390bf215546Sopenharmony_ci } 391bf215546Sopenharmony_ci return cmd->cmd_base.cmd_size; 392bf215546Sopenharmony_ci} 393bf215546Sopenharmony_ci 394bf215546Sopenharmony_ciuint32_t 395bf215546Sopenharmony_ci_mesa_unmarshal_NamedBufferSubData(struct gl_context *ctx, 396bf215546Sopenharmony_ci const struct marshal_cmd_NamedBufferSubData *cmd, 397bf215546Sopenharmony_ci const uint64_t *last) 398bf215546Sopenharmony_ci{ 399bf215546Sopenharmony_ci unreachable("never used - all BufferSubData variants use DISPATCH_CMD_BufferSubData"); 400bf215546Sopenharmony_ci return 0; 401bf215546Sopenharmony_ci} 402bf215546Sopenharmony_ci 403bf215546Sopenharmony_ciuint32_t 404bf215546Sopenharmony_ci_mesa_unmarshal_NamedBufferSubDataEXT(struct gl_context *ctx, 405bf215546Sopenharmony_ci const struct marshal_cmd_NamedBufferSubDataEXT *cmd, 406bf215546Sopenharmony_ci const uint64_t *last) 407bf215546Sopenharmony_ci{ 408bf215546Sopenharmony_ci unreachable("never used - all BufferSubData variants use DISPATCH_CMD_BufferSubData"); 409bf215546Sopenharmony_ci return 0; 410bf215546Sopenharmony_ci} 411bf215546Sopenharmony_ci 412bf215546Sopenharmony_cistatic void 413bf215546Sopenharmony_ci_mesa_marshal_BufferSubData_merged(GLuint target_or_name, GLintptr offset, 414bf215546Sopenharmony_ci GLsizeiptr size, const GLvoid *data, 415bf215546Sopenharmony_ci bool named, bool ext_dsa, const char *func) 416bf215546Sopenharmony_ci{ 417bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 418bf215546Sopenharmony_ci size_t cmd_size = sizeof(struct marshal_cmd_BufferSubData) + size; 419bf215546Sopenharmony_ci 420bf215546Sopenharmony_ci /* Fast path: Copy the data to an upload buffer, and use the GPU 421bf215546Sopenharmony_ci * to copy the uploaded data to the destination buffer. 422bf215546Sopenharmony_ci */ 423bf215546Sopenharmony_ci /* TODO: Handle offset == 0 && size < buffer_size. 424bf215546Sopenharmony_ci * If offset == 0 and size == buffer_size, it's better to discard 425bf215546Sopenharmony_ci * the buffer storage, but we don't know the buffer size in glthread. 426bf215546Sopenharmony_ci */ 427bf215546Sopenharmony_ci if (ctx->GLThread.SupportsBufferUploads && 428bf215546Sopenharmony_ci data && offset > 0 && size > 0) { 429bf215546Sopenharmony_ci struct gl_buffer_object *upload_buffer = NULL; 430bf215546Sopenharmony_ci unsigned upload_offset = 0; 431bf215546Sopenharmony_ci 432bf215546Sopenharmony_ci _mesa_glthread_upload(ctx, data, size, &upload_offset, &upload_buffer, 433bf215546Sopenharmony_ci NULL); 434bf215546Sopenharmony_ci 435bf215546Sopenharmony_ci if (upload_buffer) { 436bf215546Sopenharmony_ci _mesa_marshal_InternalBufferSubDataCopyMESA((GLintptr)upload_buffer, 437bf215546Sopenharmony_ci upload_offset, 438bf215546Sopenharmony_ci target_or_name, 439bf215546Sopenharmony_ci offset, size, named, 440bf215546Sopenharmony_ci ext_dsa); 441bf215546Sopenharmony_ci return; 442bf215546Sopenharmony_ci } 443bf215546Sopenharmony_ci } 444bf215546Sopenharmony_ci 445bf215546Sopenharmony_ci if (unlikely(size < 0 || size > INT_MAX || cmd_size < 0 || 446bf215546Sopenharmony_ci cmd_size > MARSHAL_MAX_CMD_SIZE || !data || 447bf215546Sopenharmony_ci (named && target_or_name == 0))) { 448bf215546Sopenharmony_ci _mesa_glthread_finish_before(ctx, func); 449bf215546Sopenharmony_ci if (named) { 450bf215546Sopenharmony_ci CALL_NamedBufferSubData(ctx->CurrentServerDispatch, 451bf215546Sopenharmony_ci (target_or_name, offset, size, data)); 452bf215546Sopenharmony_ci } else { 453bf215546Sopenharmony_ci CALL_BufferSubData(ctx->CurrentServerDispatch, 454bf215546Sopenharmony_ci (target_or_name, offset, size, data)); 455bf215546Sopenharmony_ci } 456bf215546Sopenharmony_ci return; 457bf215546Sopenharmony_ci } 458bf215546Sopenharmony_ci 459bf215546Sopenharmony_ci struct marshal_cmd_BufferSubData *cmd = 460bf215546Sopenharmony_ci _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_BufferSubData, 461bf215546Sopenharmony_ci cmd_size); 462bf215546Sopenharmony_ci cmd->target_or_name = target_or_name; 463bf215546Sopenharmony_ci cmd->offset = offset; 464bf215546Sopenharmony_ci cmd->size = size; 465bf215546Sopenharmony_ci cmd->named = named; 466bf215546Sopenharmony_ci cmd->ext_dsa = ext_dsa; 467bf215546Sopenharmony_ci 468bf215546Sopenharmony_ci char *variable_data = (char *) (cmd + 1); 469bf215546Sopenharmony_ci memcpy(variable_data, data, size); 470bf215546Sopenharmony_ci} 471bf215546Sopenharmony_ci 472bf215546Sopenharmony_civoid GLAPIENTRY 473bf215546Sopenharmony_ci_mesa_marshal_BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, 474bf215546Sopenharmony_ci const GLvoid * data) 475bf215546Sopenharmony_ci{ 476bf215546Sopenharmony_ci _mesa_marshal_BufferSubData_merged(target, offset, size, data, false, 477bf215546Sopenharmony_ci false, "BufferSubData"); 478bf215546Sopenharmony_ci} 479bf215546Sopenharmony_ci 480bf215546Sopenharmony_civoid GLAPIENTRY 481bf215546Sopenharmony_ci_mesa_marshal_NamedBufferSubData(GLuint buffer, GLintptr offset, 482bf215546Sopenharmony_ci GLsizeiptr size, const GLvoid * data) 483bf215546Sopenharmony_ci{ 484bf215546Sopenharmony_ci _mesa_marshal_BufferSubData_merged(buffer, offset, size, data, true, 485bf215546Sopenharmony_ci false, "NamedBufferSubData"); 486bf215546Sopenharmony_ci} 487bf215546Sopenharmony_ci 488bf215546Sopenharmony_civoid GLAPIENTRY 489bf215546Sopenharmony_ci_mesa_marshal_NamedBufferSubDataEXT(GLuint buffer, GLintptr offset, 490bf215546Sopenharmony_ci GLsizeiptr size, const GLvoid * data) 491bf215546Sopenharmony_ci{ 492bf215546Sopenharmony_ci _mesa_marshal_BufferSubData_merged(buffer, offset, size, data, true, 493bf215546Sopenharmony_ci true, "NamedBufferSubDataEXT"); 494bf215546Sopenharmony_ci} 495