VirtualBox

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

Last change on this file since 44824 was 43487, checked in by vboxsync, 12 years ago

crOpenGL/wddm: basics for miniport-based visible rects processing (guest part); export flushToHost command

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