summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostServices/SharedOpenGL/crserverlib/server_readpixels.c
blob: b53ab02b8d265124332512ba220f16125a8aa2f7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/* Copyright (c) 2001, Stanford University
 * All rights reserved
 *
 * See the file LICENSE.txt for information on redistributing this software.
 */

#include "cr_spu.h"
#include "chromium.h"
#include "cr_error.h"
#include "cr_mem.h"
#include "cr_net.h"
#include "cr_pixeldata.h"
#include "cr_unpack.h"
#include "server_dispatch.h"
#include "server.h"


void SERVER_DISPATCH_APIENTRY
crServerDispatchReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
                           GLenum format, GLenum type, GLvoid *pixels)
{
    const GLint stride = READ_DATA( 24, GLint );
    const GLint alignment = READ_DATA( 28, GLint );
    const GLint skipRows = READ_DATA( 32, GLint );
    const GLint skipPixels = READ_DATA( 36, GLint );
    const GLint bytes_per_row = READ_DATA( 40, GLint );
    const GLint rowLength = READ_DATA( 44, GLint );

    CRASSERT(bytes_per_row > 0);

#ifdef CR_ARB_pixel_buffer_object
    if (crStateIsBufferBound(GL_PIXEL_PACK_BUFFER_ARB))
    {
        GLvoid *pbo_offset;

        /*pixels are actually a pointer to location of 8byte network pointer in hgcm buffer
          regardless of guest/host bitness we're using only 4lower bytes as there're no
          pbo>4gb (yet?)
         */
        pbo_offset = (GLvoid*) ((uintptr_t) *((GLint*)pixels));

        cr_server.head_spu->dispatch_table.ReadPixels(x, y, width, height,
                                                      format, type, pbo_offset);
    }
    else
#endif
    {
        CRMessageReadPixels *rp;
        uint32_t msg_len;

        if (bytes_per_row <= 0 || height <= 0 || bytes_per_row > INT32_MAX / height)
        {
            crError("crServerDispatchReadPixels: parameters out of range");
            return;
        }

        msg_len = sizeof(*rp) + (uint32_t)bytes_per_row * height;

        rp = (CRMessageReadPixels *) crAlloc( msg_len );
        if (!rp)
        {
            crError("crServerDispatchReadPixels: out of memory");
            return;
        }

        /* Note: the ReadPixels data gets densely packed into the buffer
         * (no skip pixels, skip rows, etc.  It's up to the receiver (pack spu,
         * tilesort spu, etc) to apply the real PixelStore packing parameters.
        */
        cr_server.head_spu->dispatch_table.ReadPixels(x, y, width, height,
                                                      format, type, rp + 1);

        rp->header.type = CR_MESSAGE_READ_PIXELS;
        rp->width = width;
        rp->height = height;
        rp->bytes_per_row = bytes_per_row;
        rp->stride = stride;
        rp->format = format;
        rp->type = type;
        rp->alignment = alignment;
        rp->skipRows = skipRows;
        rp->skipPixels = skipPixels;
        rp->rowLength = rowLength;

        /* <pixels> points to the 8-byte network pointer */
        crMemcpy( &rp->pixels, pixels, sizeof(rp->pixels) );
    
        crNetSend( cr_server.curClient->conn, NULL, rp, msg_len );
        crFree( rp );
    }
}