1/*
2 * Copyright © 2013 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24/**
25 * @file wgl_per_context_funcptrs.c
26 *
27 * Tests that epoxy works correctly when wglGetProcAddress() returns
28 * different function pointers for different contexts.
29 *
30 * wgl allows that to be the case when the device or pixel format are
31 * different.  We don't know if the underlying implementation actually
32 * *will* return different function pointers, so force the issue by
33 * overriding wglGetProcAddress() to return our function pointers with
34 * magic behavior.  This way we can test epoxy's implementation
35 * regardless.
36 */
37
38#include <stdio.h>
39#include <assert.h>
40
41#include "wgl_common.h"
42#include <epoxy/gl.h>
43
44#define CREATESHADER_CTX1_VAL 1001
45#define CREATESHADER_CTX2_VAL 1002
46
47static HGLRC ctx1, ctx2, current_context;
48static bool pass = true;
49
50#define OVERRIDE_API(type) __declspec(dllexport) type __stdcall
51
52OVERRIDE_API (GLuint) override_glCreateShader_ctx1(GLenum target);
53OVERRIDE_API (GLuint) override_glCreateShader_ctx2(GLenum target);
54OVERRIDE_API (PROC) override_wglGetProcAddress(LPCSTR name);
55
56OVERRIDE_API (GLuint)
57override_glCreateShader_ctx1(GLenum target)
58{
59    if (current_context != ctx1) {
60        fputs("ctx1 called while other context current\n", stderr);
61        pass = false;
62    }
63    return CREATESHADER_CTX1_VAL;
64}
65
66OVERRIDE_API (GLuint)
67override_glCreateShader_ctx2(GLenum target)
68{
69    if (current_context != ctx2) {
70        fputs("ctx2 called while other context current\n", stderr);
71        pass = false;
72    }
73    return CREATESHADER_CTX2_VAL;
74}
75
76OVERRIDE_API (PROC)
77override_wglGetProcAddress(LPCSTR name)
78{
79    assert(strcmp(name, "glCreateShader") == 0);
80
81    if (current_context == ctx1) {
82        return (PROC)override_glCreateShader_ctx1;
83    } else {
84        assert(current_context == ctx2);
85        return (PROC)override_glCreateShader_ctx2;
86    }
87}
88
89static void
90test_createshader(HDC hdc, HGLRC ctx)
91{
92    GLuint shader, expected;
93    int ctxnum;
94
95    wglMakeCurrent(hdc, ctx);
96    current_context = ctx;
97
98    /* Install our GPA override so we can force per-context function
99     * pointers.
100     */
101    wglGetProcAddress = override_wglGetProcAddress;
102
103    if (ctx == ctx1) {
104        expected = CREATESHADER_CTX1_VAL;
105        ctxnum = 1;
106    } else {
107        assert(ctx == ctx2);
108        expected = CREATESHADER_CTX2_VAL;
109        ctxnum = 2;
110    }
111
112    shader = glCreateShader(GL_FRAGMENT_SHADER);
113    printf("ctx%d: Returned %d\n", ctxnum, shader);
114    if (shader != expected) {
115        fprintf(stderr, "  expected %d\n", expected);
116        pass = false;
117    }
118}
119
120static int
121test_function(HDC hdc)
122{
123    ctx1 = wglCreateContext(hdc);
124    ctx2 = wglCreateContext(hdc);
125    if (!ctx1 || !ctx2) {
126        fputs("Failed to create wgl contexts\n", stderr);
127        return 1;
128    }
129
130    if (!wglMakeCurrent(hdc, ctx1)) {
131        fputs("Failed to make context current\n", stderr);
132        return 1;
133    }
134
135    if (epoxy_gl_version() < 20) {
136        /* We could possibly do a 1.3 entrypoint or something instead. */
137        fputs("Test relies on overriding a GL 2.0 entrypoint\n", stderr);
138        return 77;
139    }
140
141    /* Force resolving epoxy_wglGetProcAddress. */
142    wglGetProcAddress("glCreateShader");
143
144    test_createshader(hdc, ctx1);
145    test_createshader(hdc, ctx1);
146    test_createshader(hdc, ctx2);
147    test_createshader(hdc, ctx2);
148    test_createshader(hdc, ctx1);
149    test_createshader(hdc, ctx2);
150
151    wglMakeCurrent(NULL, NULL);
152    wglDeleteContext(ctx1);
153    wglDeleteContext(ctx2);
154
155    return !pass;
156}
157
158int
159main(int argc, char **argv)
160{
161    make_window_and_test(test_function);
162
163    /* UNREACHED */
164    return 1;
165}
166