VirtualBox

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

Last change on this file since 76541 was 69392, checked in by vboxsync, 7 years ago

GuestHost/OpenGL: scm updates

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