]> git.cworth.org Git - apitrace/blob - helpers/eglsize.cpp
egl: EGL image trace support
[apitrace] / helpers / eglsize.cpp
1 /*********************************************************************
2  *
3  * Copyright 2012 Intel Corporation
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person
7  * obtaining a copy of this software and associated documentation
8  * files (the "Software"), to deal in the Software without
9  * restriction, including without limitation the rights to use, copy,
10  * modify, merge, publish, distribute, sublicense, and/or sell copies
11  * of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24  * SOFTWARE.
25  *
26  *********************************************************************/
27
28 /*
29  * Auxiliary functions to compute the size of array/blob arguments.
30  */
31 #include <string.h>
32 #include <map>
33
34 #include "os_thread.hpp"
35 #include "glimports.hpp"
36 #include "glproc.hpp"
37 #include "eglsize.hpp"
38 #include "assert.h"
39
40
41 static os::recursive_mutex image_map_mutex;
42 static std::map<EGLImageKHR, struct image_info *>image_map;
43
44 static int
45 bisect_val(int min, int max, bool is_valid_val(int val))
46 {
47     bool valid;
48
49     while (1) {
50         int try_val = min + (max - min + 1) / 2;
51
52         valid = is_valid_val(try_val);
53         if (min == max)
54             break;
55
56         if (valid)
57             min = try_val;
58         else
59             max = try_val - 1;
60     }
61
62     return valid ? min : -1;
63 }
64
65 static bool
66 is_valid_width(int val)
67 {
68     _glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, val, 1);
69     return _glGetError() == GL_NO_ERROR;
70 }
71
72 static bool
73 is_valid_height(int val)
74 {
75     _glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, val);
76     return _glGetError() == GL_NO_ERROR;
77 }
78
79 static int
80 detect_size(int *width_ret, int *height_ret)
81 {
82     static GLint max_tex_size;
83     int width;
84     int height;
85
86     if (!max_tex_size)
87         _glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size);
88
89     width = bisect_val(1, max_tex_size, is_valid_width);
90     if (width < 0)
91         return -1;
92
93     height = bisect_val(1, max_tex_size, is_valid_height);
94     if (height < 0)
95         return -1;
96
97     *width_ret = width;
98     *height_ret = height;
99
100     return 0;
101 }
102
103 void
104 _eglCreateImageKHR_get_image_info(EGLImageKHR image, struct image_info *info)
105 {
106     GLuint fbo = 0;
107     GLuint orig_fbo = 0;
108     GLuint texture = 0;
109     GLuint orig_texture;
110     GLenum status;
111
112     _glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *)&orig_fbo);
113     _glGenFramebuffers(1, &fbo);
114     _glBindFramebuffer(GL_FRAMEBUFFER, fbo);
115
116     _glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint *)&orig_texture);
117     _glGenTextures(1, &texture);
118     _glBindTexture(GL_TEXTURE_2D, texture);
119
120     _glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
121
122     memset(info, sizeof *info, 0);
123
124     _glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
125                             GL_TEXTURE_2D, texture, 0);
126     status = _glCheckFramebufferStatus(GL_FRAMEBUFFER);
127     if (status == GL_FRAMEBUFFER_COMPLETE) {
128         if (detect_size(&info->width, &info->height) != 0)
129             os::log("%s: can't detect image size\n", __func__);
130     } else {
131         os::log("%s: error: %x\n", __func__, status);
132     }
133
134     /* Don't leak errors to the traced application. */
135     (void)_glGetError();
136
137     _glBindTexture(GL_TEXTURE_2D, orig_texture);
138     _glDeleteTextures(1, &texture);
139
140     _glBindFramebuffer(GL_FRAMEBUFFER, orig_fbo);
141     _glDeleteFramebuffers(1, &fbo);
142
143     return;
144 }
145
146 static struct image_info *
147 get_image_info(EGLImageKHR image)
148 {
149     struct image_info *info;
150
151     image_map_mutex.lock();
152     info = image_map[image];
153     image_map_mutex.unlock();
154
155     return info;
156 }
157
158 void
159 _eglCreateImageKHR_epilog(EGLDisplay dpy, EGLContext ctx, EGLenum target,
160                             EGLClientBuffer buffer, const EGLint *attrib_list,
161                             EGLImageKHR image)
162 {
163     struct image_info *info;
164
165     info = (struct image_info *)malloc(sizeof *info);
166     _eglCreateImageKHR_get_image_info(image, info);
167
168     image_map_mutex.lock();
169     assert(image_map.find(image) == image_map.end());
170     image_map[image] = info;
171     image_map_mutex.unlock();
172 }
173
174 void
175 _eglDestroyImageKHR_epilog(EGLImageKHR image)
176 {
177     struct image_info *info;
178
179     info = get_image_info(image);
180
181     image_map_mutex.lock();
182     image_map.erase(image);
183     image_map_mutex.unlock();
184
185     free(info);
186 }
187
188 void
189 get_texture_2d_image(struct image_blob *blob)
190 {
191     GLuint fbo = 0;
192     GLint prev_fbo = 0;
193     GLint texture;
194     GLenum status;
195
196     _glGetIntegerv(GL_TEXTURE_BINDING_2D, &texture);
197     if (!texture)
198         return;
199
200     _glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prev_fbo);
201     _glGenFramebuffers(1, &fbo);
202     _glBindFramebuffer(GL_FRAMEBUFFER, fbo);
203
204     _glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
205                             texture, 0);
206     status = _glCheckFramebufferStatus(GL_FRAMEBUFFER);
207     if (status != GL_FRAMEBUFFER_COMPLETE)
208         os::log("%s: error: %d\n", __func__, status);
209     _glReadPixels(0, 0, blob->info.width, blob->info.height, GL_RGBA,
210                   GL_UNSIGNED_BYTE, blob->data);
211     /* Don't leak errors to the traced application. */
212     (void)_glGetError();
213
214     _glBindFramebuffer(GL_FRAMEBUFFER, prev_fbo);
215     _glDeleteFramebuffers(1, &fbo);
216 }
217
218 size_t
219 _glEGLImageTargetTexture2DOES_size(GLint target, EGLImageKHR image)
220 {
221     struct image_info *info;
222     size_t size;
223
224     info = get_image_info(image);
225     size = sizeof(struct image_blob) - 1;
226     /* We always read out the pixels in RGBA format */
227     size += info->width * info->height * 4;
228
229     return size;
230 }
231
232 void *
233 _glEGLImageTargetTexture2DOES_get_ptr(GLenum target, EGLImageKHR image)
234 {
235     GLuint tex;
236     GLuint bound_tex;
237     size_t image_blob_size = _glEGLImageTargetTexture2DOES_size(target, image);
238     struct image_blob *blob;
239     struct image_info *info;
240
241     _glGenTextures(1, &tex);
242     _glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint *)&bound_tex);
243     _glBindTexture(GL_TEXTURE_2D, tex);
244     _glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
245     blob = (struct image_blob *)malloc(image_blob_size);
246     info = get_image_info(image);
247     blob->info = *info;
248     get_texture_2d_image(blob);
249     _glBindTexture(GL_TEXTURE_2D, bound_tex);
250     _glDeleteBuffers(1, &tex);
251
252     return (void *)blob;
253 }
254
255 void
256 _glEGLImageTargetTexture2DOES_put_ptr(const void *buffer)
257 {
258     free((void *)buffer);
259 }
260