1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and/or associated documentation files (the
6 * "Materials"), to deal in the Materials without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Materials, and to
9 * permit persons to whom the Materials are furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * unaltered in all copies or substantial portions of the Materials.
14 * Any additions, deletions, or changes to the original source files
15 * must be clearly indicated in accompanying documentation.
16 *
17 * If only executable code is distributed, then the accompanying
18 * documentation must state that "this software is based in part on the
19 * work of the Khronos Group."
20 *
21 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
25 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27 * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
28 */
29
30#include "vndserver.h"
31
32#include <pixmapstr.h>
33
34#include "vndservervendor.h"
35
36static ClientPtr requestClient = NULL;
37
38void GlxSetRequestClient(ClientPtr client)
39{
40    requestClient = client;
41}
42
43static GlxServerVendor *LookupXIDMapResource(XID id)
44{
45    void *ptr = NULL;
46    int rv;
47
48    rv = dixLookupResourceByType(&ptr, id, idResource, NULL, DixReadAccess);
49    if (rv == Success) {
50        return (GlxServerVendor *) ptr;
51    } else {
52        return NULL;
53    }
54}
55
56GlxServerVendor *GlxGetXIDMap(XID id)
57{
58    GlxServerVendor *vendor = LookupXIDMapResource(id);
59
60    if (vendor == NULL) {
61        // If we haven't seen this XID before, then it may be a drawable that
62        // wasn't created through GLX, like a regular X window or pixmap. Try
63        // to look up a matching drawable to find a screen number for it.
64        void *ptr = NULL;
65        int rv = dixLookupResourceByClass(&ptr, id, RC_DRAWABLE, NULL,
66                                         DixGetAttrAccess);
67        if (rv == Success && ptr != NULL) {
68            DrawablePtr draw = (DrawablePtr) ptr;
69            vendor = GlxGetVendorForScreen(requestClient, draw->pScreen);
70        }
71    }
72    return vendor;
73}
74
75Bool GlxAddXIDMap(XID id, GlxServerVendor *vendor)
76{
77    if (id == 0 || vendor == NULL) {
78        return FALSE;
79    }
80    if (LookupXIDMapResource(id) != NULL) {
81        return FALSE;
82    }
83    return AddResource(id, idResource, vendor);
84}
85
86void GlxRemoveXIDMap(XID id)
87{
88    FreeResourceByType(id, idResource, FALSE);
89}
90
91GlxContextTagInfo *GlxAllocContextTag(ClientPtr client, GlxServerVendor *vendor)
92{
93    GlxClientPriv *cl;
94    unsigned int index;
95
96    if (vendor == NULL) {
97        return NULL;
98    }
99
100    cl = GlxGetClientData(client);
101    if (cl == NULL) {
102        return NULL;
103    }
104
105    // Look for a free tag index.
106    for (index=0; index<cl->contextTagCount; index++) {
107        if (cl->contextTags[index].vendor == NULL) {
108            break;
109        }
110    }
111    if (index >= cl->contextTagCount) {
112        // We didn't find a free entry, so grow the array.
113        GlxContextTagInfo *newTags;
114        unsigned int newSize = cl->contextTagCount * 2;
115        if (newSize == 0) {
116            // TODO: What's a good starting size for this?
117            newSize = 16;
118        }
119
120        newTags = (GlxContextTagInfo *)
121            realloc(cl->contextTags, newSize * sizeof(GlxContextTagInfo));
122        if (newTags == NULL) {
123            return NULL;
124        }
125
126        memset(&newTags[cl->contextTagCount], 0,
127                (newSize - cl->contextTagCount) * sizeof(GlxContextTagInfo));
128
129        index = cl->contextTagCount;
130        cl->contextTags = newTags;
131        cl->contextTagCount = newSize;
132    }
133
134    assert(index >= 0);
135    assert(index < cl->contextTagCount);
136    memset(&cl->contextTags[index], 0, sizeof(GlxContextTagInfo));
137    cl->contextTags[index].tag = (GLXContextTag) (index + 1);
138    cl->contextTags[index].client = client;
139    cl->contextTags[index].vendor = vendor;
140    return &cl->contextTags[index];
141}
142
143GlxContextTagInfo *GlxLookupContextTag(ClientPtr client, GLXContextTag tag)
144{
145    GlxClientPriv *cl = GlxGetClientData(client);
146    if (cl == NULL) {
147        return NULL;
148    }
149
150    if (tag > 0 && (tag - 1) < cl->contextTagCount) {
151        if (cl->contextTags[tag - 1].vendor != NULL) {
152            assert(cl->contextTags[tag - 1].client == client);
153            return &cl->contextTags[tag - 1];
154        }
155    }
156    return NULL;
157}
158
159void GlxFreeContextTag(GlxContextTagInfo *tagInfo)
160{
161    if (tagInfo != NULL) {
162        tagInfo->vendor = NULL;
163        tagInfo->vendor = NULL;
164        tagInfo->data = NULL;
165        tagInfo->context = None;
166        tagInfo->drawable = None;
167        tagInfo->readdrawable = None;
168    }
169}
170
171Bool GlxSetScreenVendor(ScreenPtr screen, GlxServerVendor *vendor)
172{
173    GlxScreenPriv *priv;
174
175    if (vendor == NULL) {
176        return FALSE;
177    }
178
179    priv = GlxGetScreen(screen);
180    if (priv == NULL) {
181        return FALSE;
182    }
183
184    if (priv->vendor != NULL) {
185        return FALSE;
186    }
187
188    priv->vendor = vendor;
189    return TRUE;
190}
191
192Bool GlxSetClientScreenVendor(ClientPtr client, ScreenPtr screen, GlxServerVendor *vendor)
193{
194    GlxClientPriv *cl;
195
196    if (screen == NULL || screen->isGPU) {
197        return FALSE;
198    }
199
200    cl = GlxGetClientData(client);
201    if (cl == NULL) {
202        return FALSE;
203    }
204
205    if (vendor != NULL) {
206        cl->vendors[screen->myNum] = vendor;
207    } else {
208        cl->vendors[screen->myNum] = GlxGetVendorForScreen(NULL, screen);
209    }
210    return TRUE;
211}
212
213GlxServerVendor *GlxGetVendorForScreen(ClientPtr client, ScreenPtr screen)
214{
215    // Note that the client won't be sending GPU screen numbers, so we don't
216    // need per-client mappings for them.
217    if (client != NULL && !screen->isGPU) {
218        GlxClientPriv *cl = GlxGetClientData(client);
219        if (cl != NULL) {
220            return cl->vendors[screen->myNum];
221        } else {
222            return NULL;
223        }
224    } else {
225        GlxScreenPriv *priv = GlxGetScreen(screen);
226        if (priv != NULL) {
227            return priv->vendor;
228        } else {
229            return NULL;
230        }
231    }
232}
233