VirtualBox

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

Last change on this file since 27244 was 15532, checked in by vboxsync, 16 years ago

crOpenGL: export to OSE

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 13.2 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 GET_PACKER_CONTEXT(pc);
262 return crPackCanHoldOpcode( pc, num_opcode, num_data );
263}
264
265
266int crPackCanHoldBoundedBuffer( const CRPackBuffer *src )
267{
268 const int len_aligned = (src->data_current - src->opcode_current - 1 + 3) & ~3;
269 GET_PACKER_CONTEXT(pc);
270 /* 24 is the size of the bounds-info packet... */
271 return crPackCanHoldOpcode( pc, 1, len_aligned + 24 );
272}
273
274void crPackAppendBuffer( const CRPackBuffer *src )
275{
276 GET_PACKER_CONTEXT(pc);
277 const int num_data = crPackNumData(src);
278 const int num_opcode = crPackNumOpcodes(src);
279
280 CRASSERT(num_data >= 0);
281 CRASSERT(num_opcode >= 0);
282
283 /* don't append onto ourself! */
284 CRASSERT(pc->currentBuffer);
285 CRASSERT(pc->currentBuffer != src);
286
287 if (!crPackCanHoldBuffer(src))
288 {
289 if (src->holds_BeginEnd)
290 {
291 crWarning( "crPackAppendBuffer: overflowed the destination!" );
292 return;
293 }
294 else
295 crError( "crPackAppendBuffer: overflowed the destination!" );
296 }
297
298 /* Copy the buffer data/operands which are at the head of the buffer */
299 crMemcpy( pc->buffer.data_current, src->data_start, num_data );
300 pc->buffer.data_current += num_data;
301
302 /* Copy the buffer opcodes which are at the tail of the buffer */
303 CRASSERT( pc->buffer.opcode_current - num_opcode >= pc->buffer.opcode_end );
304 crMemcpy( pc->buffer.opcode_current + 1 - num_opcode, src->opcode_current + 1,
305 num_opcode );
306 pc->buffer.opcode_current -= num_opcode;
307 pc->buffer.holds_BeginEnd |= src->holds_BeginEnd;
308 pc->buffer.in_BeginEnd = src->in_BeginEnd;
309 pc->buffer.holds_List |= src->holds_List;
310}
311
312
313void
314crPackAppendBoundedBuffer( const CRPackBuffer *src, const CRrecti *bounds )
315{
316 GET_PACKER_CONTEXT(pc);
317 const GLbyte *payload = (const GLbyte *) src->opcode_current + 1;
318 const int num_opcodes = crPackNumOpcodes(src);
319 const int length = src->data_current - src->opcode_current - 1;
320
321 CRASSERT(pc);
322 CRASSERT(pc->currentBuffer);
323 CRASSERT(pc->currentBuffer != src);
324
325 /*
326 * payload points to the block of opcodes immediately followed by operands.
327 */
328
329 if ( !crPackCanHoldBoundedBuffer( src ) )
330 {
331 if (src->holds_BeginEnd)
332 {
333 crWarning( "crPackAppendBoundedBuffer: overflowed the destination!" );
334 return;
335 }
336 else
337 crError( "crPackAppendBoundedBuffer: overflowed the destination!" );
338 }
339
340 if (pc->swapping)
341 crPackBoundsInfoCRSWAP( bounds, payload, length, num_opcodes );
342 else
343 crPackBoundsInfoCR( bounds, payload, length, num_opcodes );
344
345 pc->buffer.holds_BeginEnd |= src->holds_BeginEnd;
346 pc->buffer.in_BeginEnd = src->in_BeginEnd;
347 pc->buffer.holds_List |= src->holds_List;
348}
349
350
351#ifndef CHROMIUM_THREADSAFE
352static unsigned char *sanityCheckPointer = NULL;
353#endif
354
355
356/*
357 * Allocate space for a command that might be very large, such as
358 * glTexImage2D or glBufferDataARB call.
359 * The command buffer _MUST_ then be transmitted by calling crHugePacket.
360 */
361void *crPackAlloc( unsigned int size )
362{
363 GET_PACKER_CONTEXT(pc);
364 unsigned char *data_ptr;
365
366 /* include space for the length and make the payload word-aligned */
367 size = ( size + sizeof(unsigned int) + 0x3 ) & ~0x3;
368
369 if ( crPackCanHoldOpcode( pc, 1, size ) )
370 {
371 /* we can just put it in the current buffer */
372 GET_BUFFERED_POINTER(pc, size ); /* NOTE: this sets data_ptr */
373 }
374 else
375 {
376 /* Okay, it didn't fit. Maybe it will after we flush. */
377 pc->Flush( pc->flush_arg );
378 if ( crPackCanHoldOpcode( pc, 1, size ) )
379 {
380 GET_BUFFERED_POINTER(pc, size ); /* NOTE: this sets data_ptr */
381 }
382 else
383 {
384 /* It's really way too big, so allocate a temporary packet
385 * with space for the single opcode plus the payload &
386 * header.
387 */
388 data_ptr = (unsigned char *)
389 crAlloc( sizeof(CRMessageOpcodes) + 4 + size );
390
391 /* skip the header & opcode space */
392 data_ptr += sizeof(CRMessageOpcodes) + 4;
393 }
394 }
395
396 /* At the top of the function, we added four to the request size and
397 * rounded it up to the next multiple of four.
398 *
399 * At this point, we have:
400 *
401 * HIGH MEM | byte size - 1 | \
402 * ... |
403 * ... | - original 'size' bytes for data
404 * | operand data | |
405 * return value -> | operand data | /
406 * | byte 3 | \
407 * | byte 2 | |- These bytes will store 'size'
408 * | byte 1 | |
409 * data_ptr -> | byte 0 | /
410 * | CR opcode | <- Set in packspuHuge()
411 * | unused |
412 * | unused |
413 * | unused |
414 * | CRMessageOpcodes |
415 * | CRMessageOpcodes |
416 * ...
417 * | CRMessageOpcodes |
418 * | CRMessageOpcodes |
419 * LOW MEM +------------------+
420 */
421
422 if (pc->swapping)
423 {
424 *((unsigned int *) data_ptr) = SWAP32(size);
425 crDebug( "Just swapped the length, putting %d on the wire!", *((unsigned int *) data_ptr));
426 }
427 else
428 {
429 *((unsigned int *) data_ptr) = size;
430 }
431#ifndef CHROMIUM_THREADSAFE
432 sanityCheckPointer = data_ptr + 4;
433#endif
434 return data_ptr + 4;
435}
436
437#define IS_BUFFERED( packet ) \
438 ((unsigned char *) (packet) >= pc->buffer.data_start && \
439 (unsigned char *) (packet) < pc->buffer.data_end)
440
441
442/*
443 * Transmit a packet which was allocated with crPackAlloc.
444 */
445void crHugePacket( CROpcode opcode, void *packet )
446{
447 GET_PACKER_CONTEXT(pc);
448#ifndef CHROMIUM_THREADSAFE
449 CRASSERT(sanityCheckPointer == packet);
450 sanityCheckPointer = NULL;
451#endif
452
453 if ( IS_BUFFERED( packet ) )
454 WRITE_OPCODE( pc, opcode );
455 else
456 pc->SendHuge( opcode, packet );
457}
458
459void crPackFree( void *packet )
460{
461 GET_PACKER_CONTEXT(pc);
462 if ( IS_BUFFERED( packet ) )
463 return;
464
465 /* the pointer passed in doesn't include the space for the single
466 * opcode (4 bytes because of the alignment requirement) or the
467 * length field or the header */
468 crFree( (unsigned char *) packet - 8 - sizeof(CRMessageOpcodes) );
469}
470
471void crNetworkPointerWrite( CRNetworkPointer *dst, void *src )
472{
473 /* init CRNetworkPointer with invalid values */
474 dst->ptrAlign[0] = 0xDeadBeef;
475 dst->ptrAlign[1] = 0xCafeBabe;
476 /* copy the pointer's value into the CRNetworkPointer */
477 crMemcpy( dst, &src, sizeof(src) );
478
479 /* if either assertion fails, it probably means that a packer function
480 * (which returns a value) was called without setting up the writeback
481 * pointer, or something like that.
482 */
483 CRASSERT(dst->ptrAlign[0] != 0xffffffff);
484 CRASSERT(dst->ptrAlign[0] != 0xDeadBeef);
485}
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