void emit_DrawArrays_old( GLenum mode, GLint first, GLsizei count ) { __GLXcontext *gc = __glXGetCurrentContext(); const __GLXattribute * state = (const __GLXattribute *)(gc->client_state_private); struct array_state_vector * arrays = state->array_state; GLubyte * pc; size_t elements_per_request; unsigned total_requests = 0; unsigned i; size_t total_sent = 0; pc = emit_DrawArrays_header_old( gc, arrays, & elements_per_request, & total_requests, mode, count); /* Write the arrays. */ if ( total_requests == 0 ) { assert( elements_per_request >= count ); for ( i = 0 ; i < count ; i++ ) { pc = emit_element_old( pc, arrays, i + first ); } assert( pc <= gc->bufEnd ); gc->pc = pc; if ( gc->pc > gc->limit ) { (void) __glXFlushRenderBuffer(gc, gc->pc); } } else { unsigned req; for ( req = 2 ; req <= total_requests ; req++ ) { if ( count < elements_per_request ) { elements_per_request = count; } pc = gc->pc; for ( i = 0 ; i < elements_per_request ; i++ ) { pc = emit_element_old( pc, arrays, i + first ); } first += elements_per_request; total_sent += (size_t) (pc - gc->pc); __glXSendLargeChunk( gc, req, total_requests, gc->pc, pc - gc->pc ); count -= elements_per_request; } } }
/** * Send a command that is too large for the GLXRender protocol request. * * Send a large command, one that is too large for some reason to * send using the GLXRender protocol request. One reason to send * a large command is to avoid copying the data. * * \param ctx GLX context * \param header Header data. * \param headerLen Size, in bytes, of the header data. It is assumed that * the header data will always be small enough to fit in * a single X protocol packet. * \param data Command data. * \param dataLen Size, in bytes, of the command data. */ _X_HIDDEN void __glXSendLargeCommand(struct glx_context * ctx, const GLvoid * header, GLint headerLen, const GLvoid * data, GLint dataLen) { GLint maxSize; GLint totalRequests, requestNumber; /* ** Calculate the maximum amount of data can be stuffed into a single ** packet. sz_xGLXRenderReq is added because bufSize is the maximum ** packet size minus sz_xGLXRenderReq. */ maxSize = (ctx->bufSize + sz_xGLXRenderReq) - sz_xGLXRenderLargeReq; totalRequests = 1 + (dataLen / maxSize); if (dataLen % maxSize) totalRequests++; /* ** Send all of the command, except the large array, as one request. */ assert(headerLen <= maxSize); __glXSendLargeChunk(ctx, 1, totalRequests, header, headerLen); /* ** Send enough requests until the whole array is sent. */ for (requestNumber = 2; requestNumber <= (totalRequests - 1); requestNumber++) { __glXSendLargeChunk(ctx, requestNumber, totalRequests, data, maxSize); data = (const GLvoid *) (((const GLubyte *) data) + maxSize); dataLen -= maxSize; assert(dataLen > 0); } assert(dataLen <= maxSize); __glXSendLargeChunk(ctx, requestNumber, totalRequests, data, dataLen); }
void emit_DrawElements_old( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices ) { __GLXcontext *gc = __glXGetCurrentContext(); const __GLXattribute * state = (const __GLXattribute *)(gc->client_state_private); struct array_state_vector * arrays = state->array_state; GLubyte * pc; size_t elements_per_request; unsigned total_requests = 0; unsigned i; unsigned req; pc = emit_DrawArrays_header_old( gc, arrays, & elements_per_request, & total_requests, mode, count); /* Write the arrays. */ req = 2; while ( count > 0 ) { if ( count < elements_per_request ) { elements_per_request = count; } switch( type ) { case GL_UNSIGNED_INT: { const GLuint * ui_ptr = (const GLuint *) indices; for ( i = 0 ; i < elements_per_request ; i++ ) { const GLint index = (GLint) *(ui_ptr++); pc = emit_element_old( pc, arrays, index ); } break; } case GL_UNSIGNED_SHORT: { const GLushort * us_ptr = (const GLushort *) indices; for ( i = 0 ; i < elements_per_request ; i++ ) { const GLint index = (GLint) *(us_ptr++); pc = emit_element_old( pc, arrays, index ); } break; } case GL_UNSIGNED_BYTE: { const GLubyte * ub_ptr = (const GLubyte *) indices; for ( i = 0 ; i < elements_per_request ; i++ ) { const GLint index = (GLint) *(ub_ptr++); pc = emit_element_old( pc, arrays, index ); } break; } } if ( total_requests != 0 ) { __glXSendLargeChunk( gc, req, total_requests, gc->pc, pc - gc->pc ); pc = gc->pc; req++; } count -= elements_per_request; } assert( (total_requests == 0) || ((req - 1) == total_requests) ); if ( total_requests == 0 ) { assert( pc <= gc->bufEnd ); gc->pc = pc; if ( gc->pc > gc->limit ) { (void) __glXFlushRenderBuffer(gc, gc->pc); } } }
/** * Emit the header data for the GL 1.1 / EXT_vertex_arrays DrawArrays * protocol. * * \param gc GLX context. * \param arrays Array state. * \param elements_per_request Location to store the number of elements that * can fit in a single Render / RenderLarge * command. * \param total_request Total number of requests for a RenderLarge * command. If a Render command is used, this * will be zero. * \param mode Drawing mode. * \param count Number of vertices. * * \returns * A pointer to the buffer for array data. */ static GLubyte * emit_DrawArrays_header_old( __GLXcontext * gc, struct array_state_vector * arrays, size_t * elements_per_request, size_t * total_requests, GLenum mode, GLsizei count ) { size_t command_size; size_t single_vertex_size; const unsigned header_size = 16; unsigned i; GLubyte * pc; /* Determine the size of the whole command. This includes the header, * the ARRAY_INFO data and the array data. Once this size is calculated, * it will be known whether a Render or RenderLarge command is needed. */ single_vertex_size = 0; for ( i = 0 ; i < arrays->num_arrays ; i++ ) { if ( arrays->arrays[i].enabled ) { single_vertex_size += __GLX_PAD( arrays->arrays[i].element_size ); } } command_size = arrays->array_info_cache_size + header_size + (single_vertex_size * count); /* Write the header for either a Render command or a RenderLarge * command. After the header is written, write the ARRAY_INFO data. */ if ( command_size > gc->maxSmallRenderCommandSize ) { /* maxSize is the maximum amount of data can be stuffed into a single * packet. sz_xGLXRenderReq is added because bufSize is the maximum * packet size minus sz_xGLXRenderReq. */ const size_t maxSize = (gc->bufSize + sz_xGLXRenderReq) - sz_xGLXRenderLargeReq; unsigned vertex_requests; /* Calculate the number of data packets that will be required to send * the whole command. To do this, the number of verticies that * will fit in a single buffer must be calculated. * * The important value here is elements_per_request. This is the * number of complete array elements that will fit in a single * buffer. There may be some wasted space at the end of the buffer, * but splitting elements across buffer boundries would be painful. */ elements_per_request[0] = maxSize / single_vertex_size; vertex_requests = (count + elements_per_request[0] - 1) / elements_per_request[0]; *total_requests = vertex_requests + 1; __glXFlushRenderBuffer(gc, gc->pc); command_size += 4; pc = ((GLubyte *) arrays->array_info_cache) - (header_size + 4); *(uint32_t *)(pc + 0) = command_size; *(uint32_t *)(pc + 4) = X_GLrop_DrawArrays; *(uint32_t *)(pc + 8) = count; *(uint32_t *)(pc + 12) = arrays->enabled_client_array_count; *(uint32_t *)(pc + 16) = mode; __glXSendLargeChunk( gc, 1, *total_requests, pc, header_size + 4 + arrays->array_info_cache_size ); pc = gc->pc; } else { if ( (gc->pc + command_size) >= gc->bufEnd ) { (void) __glXFlushRenderBuffer(gc, gc->pc); } pc = gc->pc; *(uint16_t *)(pc + 0) = command_size; *(uint16_t *)(pc + 2) = X_GLrop_DrawArrays; *(uint32_t *)(pc + 4) = count; *(uint32_t *)(pc + 8) = arrays->enabled_client_array_count; *(uint32_t *)(pc + 12) = mode; pc += header_size; (void) memcpy( pc, arrays->array_info_cache, arrays->array_info_cache_size ); pc += arrays->array_info_cache_size; *elements_per_request = count; *total_requests = 0; } return pc; }
/** * Emit GLX DrawArrays protocol using a GLXRenderLarge packet. */ static void emit_RenderLarge_DrawArrays(__GLXcontext * gc, const struct array_info * arrays, GLsizei first, GLsizei count, GLsizei num_arrays, GLenum mode, GLsizei cmdlen, GLsizei total_vertex_size) { GLubyte * pc = gc->pc; GLsizei offset; GLsizei i; GLint maxSize; GLint totalRequests; GLint requestNumber; GLsizei elements_per_request; /* Calculate the maximum amount of data can be stuffed into a single * packet. sz_xGLXRenderReq is added because bufSize is the maximum * packet size minus sz_xGLXRenderReq. * * The important value here is elements_per_request. This is the number * of complete array elements that will fit in a single buffer. There * may be some wasted space at the end of the buffer, but splitting * elements across buffer boundries would be painful. */ maxSize = (gc->bufSize + sz_xGLXRenderReq) - sz_xGLXRenderLargeReq; elements_per_request = maxSize / total_vertex_size; totalRequests = ((count + (elements_per_request - 1)) / elements_per_request) + 1; /* Fill in the header data and send it away. */ __GLX_BEGIN_VARIABLE_LARGE(X_GLrop_DrawArrays, cmdlen+4); emit_header(pc + 8, arrays, num_arrays, count, mode); gc->pc = pc + (__GLX_DRAWARRAYS_CMD_HDR_SIZE + 4) + (__GLX_COMPONENT_HDR_SIZE * num_arrays); __glXSendLargeChunk(gc, 1, totalRequests, gc->buf, gc->pc - gc->buf); /* Write the actual array data. */ offset = 0; requestNumber = 2; for ( i = 0 ; i < count ; i++ ) { if ( i == elements_per_request ) { __glXSendLargeChunk(gc, requestNumber, totalRequests, gc->buf, offset); requestNumber++; offset = 0; count -= i; first += i; i = 0; } offset = emit_vertex(gc->buf, arrays, num_arrays, i + first, offset); } /* If the buffer isn't empty, emit the last, partial request. */ if ( offset != 0 ) { assert(requestNumber == totalRequests); __glXSendLargeChunk(gc, requestNumber, totalRequests, gc->buf, offset); } gc->pc = gc->buf; }