VirtualBox

source: vbox/trunk/src/VBox/GuestHost/OpenGL/packer/pack_buffer.c@ 34356

Last change on this file since 34356 was 34356, checked in by vboxsync, 14 years ago

crOpenGL: mt deadlock fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 13.8 KB
Line 
1/* Copyright (c) 2001, Stanford University
2 * All rights reserved
3 *
4 * See the file LICENSE.txt for information on redistributing this software.
5 */
6
7#include "cr_mem.h"
8#include "cr_string.h"
9#include "packer.h"
10#include "cr_error.h"
11#include "cr_protocol.h"
12#include "cr_unpack.h"
13
14
15void crWriteUnalignedDouble( void *buffer, double d )
16{
17 unsigned int *ui = (unsigned int *) buffer;
18 ui[0] = ((unsigned int *) &d)[0];
19 ui[1] = ((unsigned int *) &d)[1];
20}
21
22void crWriteSwappedDouble( void *buffer, double d )
23{
24 unsigned int *ui = (unsigned int *) buffer;
25 ui[0] = SWAP32(((unsigned int *) &d)[1]);
26 ui[1] = SWAP32(((unsigned int *) &d)[0]);
27}
28
29double crReadUnalignedDouble( const void *buffer )
30{
31 const unsigned int *ui = (unsigned int *) buffer;
32 double d;
33 ((unsigned int *) &d)[0] = ui[0];
34 ((unsigned int *) &d)[1] = ui[1];
35 return d;
36}
37
38/*
39 * We need the packer to run as efficiently as possible. To avoid one
40 * pointer dereference from the CRPackContext to the current CRPackBuffer,
41 * we keep a _copy_ of the current CRPackBuffer in the CRPackContext and
42 * operate on the fields in CRPackContext, rather than the CRPackBuffer.
43 *
44 * To keep things in sync, when we change a context's
45 * buffer, we have to use the crPackSet/GetBuffer() functions.
46 */
47
48void crPackSetBuffer( CRPackContext *pc, CRPackBuffer *buffer )
49{
50 CRASSERT( pc );
51 CRASSERT( buffer );
52
53 if (pc->currentBuffer == buffer)
54 return; /* re-bind is no-op */
55
56 if (pc->currentBuffer) {
57 /* Another buffer currently bound to this packer (shouldn't normally occur)
58 * Release it. Fixes Ensight issue.
59 */
60 crPackReleaseBuffer(pc);
61 }
62
63 CRASSERT( pc->currentBuffer == NULL); /* release if NULL? */
64 CRASSERT( buffer->context == NULL );
65
66 /* bind context to buffer */
67 pc->currentBuffer = buffer;
68 buffer->context = pc;
69
70 /* update the context's packing fields with those from the buffer */
71 pc->buffer = *buffer; /* struct copy */
72}
73
74/* This is useful for debugging packer problems */
75void crPackSetBufferDEBUG( const char *file, int line,
76 CRPackContext *pc, CRPackBuffer *buffer)
77
78{
79 crPackSetBuffer( pc, buffer );
80 /* record debugging info */
81 pc->file = crStrdup(file);
82 pc->line = line;
83}
84
85
86/*
87 * Release the buffer currently attached to the context.
88 * Update/resync data structures.
89 */
90void crPackReleaseBuffer( CRPackContext *pc )
91{
92 CRPackBuffer *buf;
93 CRASSERT( pc );
94
95 if (!pc->currentBuffer) {
96 crWarning("crPackReleaseBuffer called with no current buffer");
97 return; /* nothing to do */
98 }
99
100 CRASSERT( pc->currentBuffer->context == pc );
101
102 /* buffer to release */
103 buf = pc->currentBuffer;
104
105 /* copy context's fields back into the buffer to update it */
106 *buf = pc->buffer; /* struct copy */
107
108 /* unbind buffer from context */
109 buf->context = NULL;
110 pc->currentBuffer = NULL;
111
112 /* zero-out context's packing fields just to be safe */
113 crMemZero(&(pc->buffer), sizeof(pc->buffer));
114
115 /* update the debugging fields */
116 if (pc->file)
117 crFree(pc->file);
118 pc->file = NULL;
119 pc->line = -1;
120}
121
122void crPackFlushFunc( CRPackContext *pc, CRPackFlushFunc ff )
123{
124 pc->Flush = ff;
125}
126
127void crPackFlushArg( CRPackContext *pc, void *flush_arg )
128{
129 pc->flush_arg = flush_arg;
130}
131
132void crPackSendHugeFunc( CRPackContext *pc, CRPackSendHugeFunc shf )
133{
134 pc->SendHuge = shf;
135}
136
137/*
138 * This basically resets the buffer attached to <pc> to the default, empty
139 * state.
140 */
141void crPackResetPointers( CRPackContext *pc )
142{
143 const GLboolean geom_only = pc->buffer.geometry_only; /* save this flag */
144 const GLboolean holds_BeginEnd = pc->buffer.holds_BeginEnd;
145 const GLboolean in_BeginEnd = pc->buffer.in_BeginEnd;
146 const GLboolean canBarf = pc->buffer.canBarf;
147 CRPackBuffer *buf = pc->currentBuffer;
148 CRASSERT(buf);
149 crPackInitBuffer( buf, buf->pack, buf->size, buf->mtu );
150 pc->buffer.geometry_only = geom_only; /* restore the flag */
151 pc->buffer.holds_BeginEnd = holds_BeginEnd;
152 pc->buffer.in_BeginEnd = in_BeginEnd;
153 pc->buffer.canBarf = canBarf;
154}
155
156
157/**
158 * Return max number of opcodes that'll fit in the given buffer size.
159 * Each opcode has at least a 1-word payload, so opcodes can occupy at most
160 * 20% of the space.
161 */
162int
163crPackMaxOpcodes( int buffer_size )
164{
165 int n = ( buffer_size - sizeof(CRMessageOpcodes) ) / 5;
166 /* Don't forget to add one here in case the buffer size is not
167 * divisible by 4. Thanks to Ken Moreland for finding this.
168 */
169 n++;
170 /* round up to multiple of 4 */
171 n = (n + 0x3) & (~0x3);
172 return n;
173}
174
175
176/**
177 * Return max number of data bytes that'll fit in the given buffer size.
178 */
179int
180crPackMaxData( int buffer_size )
181{
182 int n = buffer_size - sizeof(CRMessageOpcodes);
183 n -= crPackMaxOpcodes(buffer_size);
184 return n;
185}
186
187
188/**
189 * Initialize the given CRPackBuffer object.
190 * The buffer may or may not be currently bound to a CRPackContext.
191 *
192 * Opcodes and operands are packed into a buffer in a special way.
193 * Opcodes start at opcode_start and go downward in memory while operands
194 * start at data_start and go upward in memory. The buffer is full when we
195 * either run out of opcode space or operand space.
196 *
197 * Diagram (memory addresses increase upward):
198 *
199 * data_end -> | | <- buf->pack + buf->size
200 * +---------+
201 * | |
202 * | |
203 * | operands|
204 * | |
205 * | |
206 * data_start -> +---------+
207 * opcode_start -> | |
208 * | |
209 * | opcodes |
210 * | |
211 * | |
212 * opcode_end -> +---------+ <- buf->pack
213 *
214 * \param buf the CRPackBuffer to initialize
215 * \param pack the address of the buffer for packing opcodes/operands.
216 * \param size size of the buffer, in bytes
217 * \param mtu max transmission unit size, in bytes. When the buffer
218 * has 'mtu' bytes in it, we have to send it. The MTU might
219 * be somewhat smaller than the buffer size.
220 */
221void crPackInitBuffer( CRPackBuffer *buf, void *pack, int size, int mtu )
222{
223 unsigned int num_opcodes;
224
225 CRASSERT(mtu <= size);
226
227 buf->size = size;
228 buf->mtu = mtu;
229 buf->pack = pack;
230
231 num_opcodes = crPackMaxOpcodes( buf->size );
232
233 buf->data_start =
234 (unsigned char *) buf->pack + num_opcodes + sizeof(CRMessageOpcodes);
235 buf->data_current = buf->data_start;
236 buf->data_end = (unsigned char *) buf->pack + buf->size;
237
238 buf->opcode_start = buf->data_start - 1;
239 buf->opcode_current = buf->opcode_start;
240 buf->opcode_end = buf->opcode_start - num_opcodes;
241
242 buf->geometry_only = GL_FALSE;
243 buf->holds_BeginEnd = GL_FALSE;
244 buf->in_BeginEnd = GL_FALSE;
245 buf->canBarf = GL_FALSE;
246
247 if (buf->context) {
248 /* Also reset context's packing fields */
249 CRPackContext *pc = buf->context;
250 CRASSERT(pc->currentBuffer == buf);
251 /*crMemcpy( &(pc->buffer), buf, sizeof(*buf) );*/
252 pc->buffer = *buf;
253 }
254}
255
256
257int crPackCanHoldBuffer( const CRPackBuffer *src )
258{
259 const int num_data = crPackNumData(src);
260 const int num_opcode = crPackNumOpcodes(src);
261 int res;
262 CR_GET_PACKER_CONTEXT(pc);
263 CR_LOCK_PACKER_CONTEXT(pc);
264 res = crPackCanHoldOpcode( pc, num_opcode, num_data );
265 CR_UNLOCK_PACKER_CONTEXT(pc);
266 return res;
267}
268
269
270int crPackCanHoldBoundedBuffer( const CRPackBuffer *src )
271{
272 const int len_aligned = (src->data_current - src->opcode_current - 1 + 3) & ~3;
273 CR_GET_PACKER_CONTEXT(pc);
274 /* 24 is the size of the bounds-info packet... */
275 return crPackCanHoldOpcode( pc, 1, len_aligned + 24 );
276}
277
278void crPackAppendBuffer( const CRPackBuffer *src )
279{
280 CR_GET_PACKER_CONTEXT(pc);
281 const int num_data = crPackNumData(src);
282 const int num_opcode = crPackNumOpcodes(src);
283
284 CRASSERT(num_data >= 0);
285 CRASSERT(num_opcode >= 0);
286
287 CR_LOCK_PACKER_CONTEXT(pc);
288
289 /* don't append onto ourself! */
290 CRASSERT(pc->currentBuffer);
291 CRASSERT(pc->currentBuffer != src);
292
293 if (!crPackCanHoldBuffer(src))
294 {
295 if (src->holds_BeginEnd)
296 {
297 crWarning( "crPackAppendBuffer: overflowed the destination!" );
298 CR_UNLOCK_PACKER_CONTEXT(pc);
299 return;
300 }
301 else
302 {
303 crError( "crPackAppendBuffer: overflowed the destination!" );
304 CR_UNLOCK_PACKER_CONTEXT(pc);
305 }
306 }
307
308 /* Copy the buffer data/operands which are at the head of the buffer */
309 crMemcpy( pc->buffer.data_current, src->data_start, num_data );
310 pc->buffer.data_current += num_data;
311
312 /* Copy the buffer opcodes which are at the tail of the buffer */
313 CRASSERT( pc->buffer.opcode_current - num_opcode >= pc->buffer.opcode_end );
314 crMemcpy( pc->buffer.opcode_current + 1 - num_opcode, src->opcode_current + 1,
315 num_opcode );
316 pc->buffer.opcode_current -= num_opcode;
317 pc->buffer.holds_BeginEnd |= src->holds_BeginEnd;
318 pc->buffer.in_BeginEnd = src->in_BeginEnd;
319 pc->buffer.holds_List |= src->holds_List;
320 CR_UNLOCK_PACKER_CONTEXT(pc);
321}
322
323
324void
325crPackAppendBoundedBuffer( const CRPackBuffer *src, const CRrecti *bounds )
326{
327 CR_GET_PACKER_CONTEXT(pc);
328 const GLbyte *payload = (const GLbyte *) src->opcode_current + 1;
329 const int num_opcodes = crPackNumOpcodes(src);
330 const int length = src->data_current - src->opcode_current - 1;
331
332 CRASSERT(pc);
333 CR_LOCK_PACKER_CONTEXT(pc);
334 CRASSERT(pc->currentBuffer);
335 CRASSERT(pc->currentBuffer != src);
336
337 /*
338 * payload points to the block of opcodes immediately followed by operands.
339 */
340
341 if ( !crPackCanHoldBoundedBuffer( src ) )
342 {
343 if (src->holds_BeginEnd)
344 {
345 crWarning( "crPackAppendBoundedBuffer: overflowed the destination!" );
346 CR_UNLOCK_PACKER_CONTEXT(pc);
347 return;
348 }
349 else
350 {
351 crError( "crPackAppendBoundedBuffer: overflowed the destination!" );
352 CR_UNLOCK_PACKER_CONTEXT(pc);
353 }
354 }
355
356 if (pc->swapping)
357 crPackBoundsInfoCRSWAP( bounds, payload, length, num_opcodes );
358 else
359 crPackBoundsInfoCR( bounds, payload, length, num_opcodes );
360
361 pc->buffer.holds_BeginEnd |= src->holds_BeginEnd;
362 pc->buffer.in_BeginEnd = src->in_BeginEnd;
363 pc->buffer.holds_List |= src->holds_List;
364 CR_UNLOCK_PACKER_CONTEXT(pc);
365}
366
367
368#ifndef CHROMIUM_THREADSAFE
369static unsigned char *sanityCheckPointer = NULL;
370#endif
371
372
373/*
374 * Allocate space for a command that might be very large, such as
375 * glTexImage2D or glBufferDataARB call.
376 * The command buffer _MUST_ then be transmitted by calling crHugePacket.
377 */
378void *crPackAlloc( unsigned int size )
379{
380 CR_GET_PACKER_CONTEXT(pc);
381 unsigned char *data_ptr;
382
383 /* include space for the length and make the payload word-aligned */
384 size = ( size + sizeof(unsigned int) + 0x3 ) & ~0x3;
385
386 CR_LOCK_PACKER_CONTEXT(pc);
387
388 if ( crPackCanHoldOpcode( pc, 1, size ) )
389 {
390 /* we can just put it in the current buffer */
391 CR_GET_BUFFERED_POINTER_NOLOCK(pc, size ); /* NOTE: this sets data_ptr */
392 }
393 else
394 {
395 /* Okay, it didn't fit. Maybe it will after we flush. */
396 CR_UNLOCK_PACKER_CONTEXT(pc)
397 pc->Flush( pc->flush_arg );
398 CR_LOCK_PACKER_CONTEXT(pc);
399 if ( crPackCanHoldOpcode( pc, 1, size ) )
400 {
401 CR_GET_BUFFERED_POINTER_NOLOCK(pc, size ); /* NOTE: this sets data_ptr */
402 }
403 else
404 {
405 /* It's really way too big, so allocate a temporary packet
406 * with space for the single opcode plus the payload &
407 * header.
408 */
409 data_ptr = (unsigned char *)
410 crAlloc( sizeof(CRMessageOpcodes) + 4 + size );
411
412 /* skip the header & opcode space */
413 data_ptr += sizeof(CRMessageOpcodes) + 4;
414 }
415 }
416
417 /* At the top of the function, we added four to the request size and
418 * rounded it up to the next multiple of four.
419 *
420 * At this point, we have:
421 *
422 * HIGH MEM | byte size - 1 | \
423 * ... |
424 * ... | - original 'size' bytes for data
425 * | operand data | |
426 * return value -> | operand data | /
427 * | byte 3 | \
428 * | byte 2 | |- These bytes will store 'size'
429 * | byte 1 | |
430 * data_ptr -> | byte 0 | /
431 * | CR opcode | <- Set in packspuHuge()
432 * | unused |
433 * | unused |
434 * | unused |
435 * | CRMessageOpcodes |
436 * | CRMessageOpcodes |
437 * ...
438 * | CRMessageOpcodes |
439 * | CRMessageOpcodes |
440 * LOW MEM +------------------+
441 */
442
443 if (pc->swapping)
444 {
445 *((unsigned int *) data_ptr) = SWAP32(size);
446 crDebug( "Just swapped the length, putting %d on the wire!", *((unsigned int *) data_ptr));
447 }
448 else
449 {
450 *((unsigned int *) data_ptr) = size;
451 }
452#ifndef CHROMIUM_THREADSAFE
453 sanityCheckPointer = data_ptr + 4;
454#endif
455 return data_ptr + 4;
456}
457
458#define IS_BUFFERED( packet ) \
459 ((unsigned char *) (packet) >= pc->buffer.data_start && \
460 (unsigned char *) (packet) < pc->buffer.data_end)
461
462
463/*
464 * Transmit a packet which was allocated with crPackAlloc.
465 */
466void crHugePacket( CROpcode opcode, void *packet )
467{
468 CR_GET_PACKER_CONTEXT(pc);
469#ifndef CHROMIUM_THREADSAFE
470 CRASSERT(sanityCheckPointer == packet);
471 sanityCheckPointer = NULL;
472#endif
473
474 if ( IS_BUFFERED( packet ) )
475 WRITE_OPCODE( pc, opcode );
476 else
477 pc->SendHuge( opcode, packet );
478}
479
480void crPackFree( void *packet )
481{
482 CR_GET_PACKER_CONTEXT(pc);
483
484 if ( IS_BUFFERED( packet ) )
485 {
486 CR_UNLOCK_PACKER_CONTEXT(pc);
487 return;
488 }
489
490 CR_UNLOCK_PACKER_CONTEXT(pc);
491
492 /* the pointer passed in doesn't include the space for the single
493 * opcode (4 bytes because of the alignment requirement) or the
494 * length field or the header */
495 crFree( (unsigned char *) packet - 8 - sizeof(CRMessageOpcodes) );
496}
497
498void crNetworkPointerWrite( CRNetworkPointer *dst, void *src )
499{
500 /* init CRNetworkPointer with invalid values */
501 dst->ptrAlign[0] = 0xDeadBeef;
502 dst->ptrAlign[1] = 0xCafeBabe;
503 /* copy the pointer's value into the CRNetworkPointer */
504 crMemcpy( dst, &src, sizeof(src) );
505
506 /* if either assertion fails, it probably means that a packer function
507 * (which returns a value) was called without setting up the writeback
508 * pointer, or something like that.
509 */
510 CRASSERT(dst->ptrAlign[0] != 0xffffffff);
511 CRASSERT(dst->ptrAlign[0] != 0xDeadBeef);
512}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette