Panda3D
Loading...
Searching...
No Matches
eglGraphicsPixmap.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file eglGraphicsPixmap.cxx
10 * @author rdb
11 * @date 2009-06-13
12 */
13
14#include "eglGraphicsPixmap.h"
15
16#ifdef USE_X11
17
18#include "eglGraphicsWindow.h"
20#include "config_egldisplay.h"
21#include "eglGraphicsPipe.h"
22
23#include "graphicsPipe.h"
24#include "pStatTimer.h"
25
26TypeHandle eglGraphicsPixmap::_type_handle;
27
28/**
29 *
30 */
31eglGraphicsPixmap::
32eglGraphicsPixmap(GraphicsEngine *engine, GraphicsPipe *pipe,
33 const std::string &name,
34 const FrameBufferProperties &fb_prop,
35 const WindowProperties &win_prop,
36 int flags,
38 GraphicsOutput *host) :
39 GraphicsBuffer(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
40{
41 eglGraphicsPipe *egl_pipe;
42 DCAST_INTO_V(egl_pipe, _pipe);
43 _egl_display = egl_pipe->get_egl_display();
44 _drawable = None;
45 _x_pixmap = None;
46 _egl_surface = EGL_NO_SURFACE;
47
48 // Since the pixmap never gets flipped, we get screenshots from the same
49 // pixmap we draw into.
50 _screenshot_buffer_type = _draw_buffer_type;
51}
52
53/**
54 *
55 */
56eglGraphicsPixmap::
57~eglGraphicsPixmap() {
58 nassertv(_x_pixmap == None && _egl_surface == EGL_NO_SURFACE);
59}
60
61/**
62 * This function will be called within the draw thread before beginning
63 * rendering for a given frame. It should do whatever setup is required, and
64 * return true if the frame should be rendered, or false if it should be
65 * skipped.
66 */
67bool eglGraphicsPixmap::
68begin_frame(FrameMode mode, Thread *current_thread) {
69 PStatTimer timer(_make_current_pcollector, current_thread);
70
71 begin_frame_spam(mode);
72 if (_gsg == nullptr) {
73 return false;
74 }
75
77 DCAST_INTO_R(eglgsg, _gsg, false);
78 if (!eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, eglgsg->_context)) {
79 egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
80 << get_egl_error_string(eglGetError()) << "\n";
81 }
82
83 // Now that we have made the context current to a window, we can reset the
84 // GSG state if this is the first time it has been used. (We can't just
85 // call reset() when we construct the GSG, because reset() requires having a
86 // current context.)
87 eglgsg->reset_if_new();
88
89 if (mode == FM_render) {
90 CDLockedReader cdata(_cycler);
91 for (size_t i = 0; i != cdata->_textures.size(); ++i) {
92 const RenderTexture &rt = cdata->_textures[i];
93 RenderTextureMode rtm_mode = rt._rtm_mode;
94 if (rtm_mode == RTM_bind_or_copy) {
95 CDWriter cdataw(_cycler, cdata, false);
96 nassertr(cdata->_textures.size() == cdataw->_textures.size(), false);
97 cdataw->_textures[i]._rtm_mode = RTM_copy_texture;
98 }
99 }
100 clear_cube_map_selection();
101 }
102
103 _gsg->set_current_properties(&get_fb_properties());
104 return _gsg->begin_frame(current_thread);
105}
106
107/**
108 * This function will be called within the draw thread after rendering is
109 * completed for a given frame. It should do whatever finalization is
110 * required.
111 */
112void eglGraphicsPixmap::
113end_frame(FrameMode mode, Thread *current_thread) {
114 end_frame_spam(mode);
115 nassertv(_gsg != nullptr);
116
117 if (mode == FM_render) {
118 copy_to_textures();
119 }
120
121 _gsg->end_frame(current_thread);
122
123 if (mode == FM_render) {
124 trigger_flip();
125 clear_cube_map_selection();
126 }
127}
128
129/**
130 * Closes the pixmap right now. Called from the window thread.
131 */
132void eglGraphicsPixmap::
133close_buffer() {
134 if (_gsg != nullptr) {
135 if (!eglMakeCurrent(_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
136 egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
137 << get_egl_error_string(eglGetError()) << "\n";
138 }
139 _gsg.clear();
140 }
141
142 if (_egl_surface != EGL_NO_SURFACE) {
143 if (!eglDestroySurface(_egl_display, _egl_surface)) {
144 egldisplay_cat.error() << "Failed to destroy surface: "
145 << get_egl_error_string(eglGetError()) << "\n";
146 }
147 _egl_surface = EGL_NO_SURFACE;
148 }
149
150 if (_x_pixmap != None) {
151 XFreePixmap(_display, _x_pixmap);
152 _x_pixmap = None;
153 }
154
155 _is_valid = false;
156}
157
158/**
159 * Opens the pixmap right now. Called from the window thread. Returns true
160 * if the pixmap is successfully opened, or false if there was a problem.
161 */
162bool eglGraphicsPixmap::
163open_buffer() {
164 eglGraphicsPipe *egl_pipe;
165 DCAST_INTO_R(egl_pipe, _pipe, false);
166
167 // GSG CreationInitialization
169 if (_gsg == 0) {
170 // There is no old gsg. Create a new one.
171 eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, nullptr);
172 eglgsg->choose_pixel_format(_fb_properties, egl_pipe, false, false, true);
173 _gsg = eglgsg;
174 } else {
175 // If the old gsg has the wrong pixel format, create a new one that shares
176 // with the old gsg.
177 DCAST_INTO_R(eglgsg, _gsg, false);
178 if (!eglgsg->get_fb_properties().subsumes(_fb_properties)) {
179 eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, eglgsg);
180 eglgsg->choose_pixel_format(_fb_properties, egl_pipe, false, false, true);
181 _gsg = eglgsg;
182 }
183 }
184
185 if (eglgsg->_fbconfig == None) {
186 // If we didn't use an fbconfig to create the GSG, we can't create a
187 // PBuffer.
188 return false;
189 }
190
191 XVisualInfo *visual_info = eglgsg->_visual;
192 if (visual_info == nullptr) {
193 // No X visual for this fbconfig; how can we create the pixmap?
194 egldisplay_cat.error()
195 << "No X visual: cannot create pixmap.\n";
196 return false;
197 }
198
199 _display = egl_pipe->get_display();
200 _drawable = egl_pipe->get_root();
201 if (_host != nullptr) {
202 if (_host->is_of_type(eglGraphicsWindow::get_class_type())) {
203 eglGraphicsWindow *win = DCAST(eglGraphicsWindow, _host);
204 _drawable = win->get_xwindow();
205 } else if (_host->is_of_type(eglGraphicsPixmap::get_class_type())) {
206 eglGraphicsPixmap *pix = DCAST(eglGraphicsPixmap, _host);
207 _drawable = pix->_drawable;
208 }
209 }
210
211 _x_pixmap = XCreatePixmap(_display, _drawable,
212 _size.get_x(), _size.get_y(), visual_info->depth);
213 if (_x_pixmap == None) {
214 egldisplay_cat.error()
215 << "Failed to create X pixmap.\n";
216 close_buffer();
217 return false;
218 }
219
220 nassertr(eglgsg->_fbconfig, false);
221 _egl_surface = eglCreatePixmapSurface(_egl_display, eglgsg->_fbconfig, (NativePixmapType) _x_pixmap, nullptr);
222
223 if (_egl_surface == EGL_NO_SURFACE) {
224 egldisplay_cat.error()
225 << "Failed to create EGL pixmap surface:"
226 << get_egl_error_string(eglGetError()) << "\n";
227 close_buffer();
228 return false;
229 }
230
231 eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, eglgsg->_context);
232 eglgsg->reset_if_new();
233 if (!eglgsg->is_valid()) {
234 close_buffer();
235 return false;
236 }
238 (_fb_properties, eglgsg->get_gl_renderer())) {
239 close_buffer();
240 return false;
241 }
242 _fb_properties = eglgsg->get_fb_properties();
243
244 _is_valid = true;
245 return true;
246}
247
248#endif // USE_X11
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
bool verify_hardware_software(const FrameBufferProperties &props, const std::string &renderer) const
Validates that the properties represent the desired kind of renderer (hardware or software).
bool subsumes(const FrameBufferProperties &other) const
Returns true if this set of properties makes strictly greater or equal demands of the framebuffer tha...
An offscreen buffer for rendering into.
This class is the main interface to controlling the render process.
This is a base class for the various different classes that represent the result of a frame of render...
An object to create GraphicsOutputs that share a particular 3-D API.
Encapsulates all the communication with a particular instance of a given rendering backend.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition pStatTimer.h:30
A thread; that is, a lightweight process.
Definition thread.h:46
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
A container for the various kinds of properties we might ask to have on a graphics window before we o...
This graphics pipe represents the interface for creating OpenGL ES graphics windows on an X-based (e....
A tiny specialization on GLESGraphicsStateGuardian to add some egl-specific information.
const FrameBufferProperties & get_fb_properties() const
Gets the FrameBufferProperties for all windows and buffers that use this GSG.
void choose_pixel_format(const FrameBufferProperties &properties, eglGraphicsPipe *egl_pipe, bool need_window, bool need_pbuffer, bool need_pixmap)
Selects a visual or fbconfig for all the windows and buffers that use this gsg.
const std::string get_egl_error_string(int error)
Returns the given EGL error as string.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.