def __init__(self, display: Union[str, int], qml_view: QUrl, gl_context: QOpenGLContext): super().__init__() self.qml_view = qml_view self.display = display self.wl_display = Display(display) self.wl_compositor = None self.wl_shm = None self.wl_embedder = None self.views = {} self.fd_notifier = None self.engine = Engine() self.component = None self.qml_view = qml_view self.connected = False self.gl_context = gl_context assert gl_context.isOpenGLES() surface = QOffscreenSurface() surface.setFormat(gl_context.format()) surface.create() gl_context.makeCurrent(surface)
class RenderWindow(QWindow): def __init__(self, format): super(RenderWindow, self).__init__() self.setSurfaceType(QWindow.OpenGLSurface) self.setFormat(format) self.context = QOpenGLContext(self) self.context.setFormat(self.requestedFormat()) if not self.context.create(): raise Exception("Unable to create GL context") self.program = None self.timer = None self.angle = 0 def initGl(self): self.program = QOpenGLShaderProgram(self) self.vao = QOpenGLVertexArrayObject() self.vbo = QOpenGLBuffer() format = self.context.format() useNewStyleShader = format.profile() == QSurfaceFormat.CoreProfile # Try to handle 3.0 & 3.1 that do not have the core/compatibility profile # concept 3.2+ has. This may still fail since version 150 (3.2) is # specified in the sources but it's worth a try. if (format.renderableType() == QSurfaceFormat.OpenGL and format.majorVersion() == 3 and format.minorVersion() <= 1): useNewStyleShader = not format.testOption(QSurfaceFormat.DeprecatedFunctions) vertexShader = vertexShaderSource if useNewStyleShader else vertexShaderSource110 fragmentShader = fragmentShaderSource if useNewStyleShader else fragmentShaderSource110 if not self.program.addShaderFromSourceCode(QOpenGLShader.Vertex, vertexShader): raise Exception("Vertex shader could not be added: {} ({})".format(self.program.log(), vertexShader)) if not self.program.addShaderFromSourceCode(QOpenGLShader.Fragment, fragmentShader): raise Exception("Fragment shader could not be added: {} ({})".format(self.program.log(), fragmentShader)) if not self.program.link(): raise Exception("Could not link shaders: {}".format(self.program.log())) self.posAttr = self.program.attributeLocation("posAttr") self.colAttr = self.program.attributeLocation("colAttr") self.matrixUniform = self.program.uniformLocation("matrix") self.vbo.create() self.vbo.bind() self.verticesData = vertices.tobytes() self.colorsData = colors.tobytes() verticesSize = 4 * vertices.size colorsSize = 4 * colors.size self.vbo.allocate(VoidPtr(self.verticesData), verticesSize + colorsSize) self.vbo.write(verticesSize, VoidPtr(self.colorsData), colorsSize) self.vbo.release() vaoBinder = QOpenGLVertexArrayObject.Binder(self.vao) if self.vao.isCreated(): # have VAO support, use it self.setupVertexAttribs() def setupVertexAttribs(self): self.vbo.bind() self.program.setAttributeBuffer(self.posAttr, GL.GL_FLOAT, 0, 2) self.program.setAttributeBuffer(self.colAttr, GL.GL_FLOAT, 4 * vertices.size, 3) self.program.enableAttributeArray(self.posAttr) self.program.enableAttributeArray(self.colAttr) self.vbo.release() def exposeEvent(self, event): if self.isExposed(): self.render() if self.timer is None: self.timer = QTimer(self) self.timer.timeout.connect(self.slotTimer) if not self.timer.isActive(): self.timer.start(10) else: if self.timer and self.timer.isActive(): self.timer.stop() def render(self): if not self.context.makeCurrent(self): raise Exception("makeCurrent() failed") functions = self.context.functions() if self.program is None: functions.glEnable(GL.GL_DEPTH_TEST) functions.glClearColor(0, 0, 0, 1) self.initGl() retinaScale = self.devicePixelRatio() functions.glViewport(0, 0, self.width() * retinaScale, self.height() * retinaScale) functions.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT) self.program.bind() matrix = QMatrix4x4() matrix.perspective(60, 4 / 3, 0.1, 100) matrix.translate(0, 0, -2) matrix.rotate(self.angle, 0, 1, 0) self.program.setUniformValue(self.matrixUniform, matrix) if self.vao.isCreated(): self.vao.bind() else: # no VAO support, set the vertex attribute arrays now self.setupVertexAttribs() functions.glDrawArrays(GL.GL_TRIANGLES, 0, 3) self.vao.release() self.program.release() # swapInterval is 1 by default which means that swapBuffers() will (hopefully) block # and wait for vsync. self.context.swapBuffers(self) self.context.doneCurrent() def slotTimer(self): self.render() self.angle += 1 def glInfo(self): if not self.context.makeCurrent(self): raise Exception("makeCurrent() failed") functions = self.context.functions() text = """Vendor: {}\nRenderer: {}\nVersion: {}\nShading language: {} \nContext Format: {}\n\nSurface Format: {}""".format( functions.glGetString(GL.GL_VENDOR), functions.glGetString(GL.GL_RENDERER), functions.glGetString(GL.GL_VERSION), functions.glGetString(GL.GL_SHADING_LANGUAGE_VERSION), print_surface_format(self.context.format()), print_surface_format(self.format())) self.context.doneCurrent() return text
class RenderWindow(QWindow): def __init__(self, format): super(RenderWindow, self).__init__() self.setSurfaceType(QWindow.OpenGLSurface) self.setFormat(format) self.context = QOpenGLContext(self) self.context.setFormat(self.requestedFormat()) if not self.context.create(): raise Exception("Unable to create GL context") self.program = None self.timer = None self.angle = 0 def initGl(self): self.program = QOpenGLShaderProgram(self) self.vao = QOpenGLVertexArrayObject() self.vbo = QOpenGLBuffer() format = self.context.format() useNewStyleShader = format.profile() == QSurfaceFormat.CoreProfile # Try to handle 3.0 & 3.1 that do not have the core/compatibility profile # concept 3.2+ has. This may still fail since version 150 (3.2) is # specified in the sources but it's worth a try. if (format.renderableType() == QSurfaceFormat.OpenGL and format.majorVersion() == 3 and format.minorVersion() <= 1): useNewStyleShader = not format.testOption(QSurfaceFormat.DeprecatedFunctions) vertexShader = vertexShaderSource if useNewStyleShader else vertexShaderSource110 fragmentShader = fragmentShaderSource if useNewStyleShader else fragmentShaderSource110 if not self.program.addShaderFromSourceCode(QOpenGLShader.Vertex, vertexShader): raise Exception("Vertex shader could not be added: {} ({})".format(self.program.log(), vertexShader)) if not self.program.addShaderFromSourceCode(QOpenGLShader.Fragment, fragmentShader): raise Exception("Fragment shader could not be added: {} ({})".format(self.program.log(), fragmentShader)) if not self.program.link(): raise Exception("Could not link shaders: {}".format(self.program.log())) self.posAttr = self.program.attributeLocation("posAttr") self.colAttr = self.program.attributeLocation("colAttr") self.matrixUniform = self.program.uniformLocation("matrix") self.vbo.create() self.vbo.bind() self.verticesData = vertices.tobytes() self.colorsData = colors.tobytes() verticesSize = 4 * vertices.size colorsSize = 4 * colors.size self.vbo.allocate(VoidPtr(self.verticesData), verticesSize + colorsSize) self.vbo.write(verticesSize, VoidPtr(self.colorsData), colorsSize) self.vbo.release() vaoBinder = QOpenGLVertexArrayObject.Binder(self.vao) if self.vao.isCreated(): # have VAO support, use it self.setupVertexAttribs() def setupVertexAttribs(self): self.vbo.bind() self.program.setAttributeBuffer(self.posAttr, GL.GL_FLOAT, 0, 2) self.program.setAttributeBuffer(self.colAttr, GL.GL_FLOAT, 4 * vertices.size, 3) self.program.enableAttributeArray(self.posAttr) self.program.enableAttributeArray(self.colAttr) self.vbo.release() def exposeEvent(self, event): if self.isExposed(): self.render() if self.timer is None: self.timer = QTimer(self) self.timer.timeout.connect(self.slotTimer) self.timer.start(10) def render(self): if not self.context.makeCurrent(self): raise Exception("makeCurrent() failed") functions = self.context.functions() if self.program is None: functions.glEnable(GL.GL_DEPTH_TEST) functions.glClearColor(0, 0, 0, 1) self.initGl() functions.glViewport(0, 0, self.width(), self.height()) functions.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT) self.program.bind() matrix = QMatrix4x4() matrix.perspective(60, 4 / 3, 0.1, 100) matrix.translate(0, 0, -2) matrix.rotate(self.angle, 0, 1, 0) self.program.setUniformValue(self.matrixUniform, matrix) if self.vao.isCreated(): self.vao.bind() else: # no VAO support, set the vertex attribute arrays now self.setupVertexAttribs() functions.glDrawArrays(GL.GL_TRIANGLES, 0, 3) self.vao.release() self.program.release() # swapInterval is 1 by default which means that swapBuffers() will (hopefully) block # and wait for vsync. self.context.swapBuffers(self) self.context.doneCurrent() def slotTimer(self): self.render() self.angle += 1 def glInfo(self): if not self.context.makeCurrent(self): raise Exception("makeCurrent() failed") functions = self.context.functions() text = "Vendor: {}\nRenderer: {}\nVersion: {}\nShading language: {}".format( functions.glGetString(GL.GL_VENDOR), functions.glGetString(GL.GL_RENDERER), functions.glGetString(GL.GL_VERSION), functions.glGetString(GL.GL_SHADING_LANGUAGE_VERSION)) self.context.doneCurrent() return text
def initialize(self, size: QSize, shareContext: QOpenGLContext) -> None: """ Initialize offscreen renderer. Args: size: The size of the area available for rendering. shareContext: OpenGL context used as a share context. Raises: RuntimeError: If the renderer has already been initialized. """ print(f'QmlOffscreenRenderer.initialize: {size}') if self.initialized: raise RuntimeError('Already initialized') context = QOpenGLContext() context.setShareContext(shareContext) context.setFormat(get_default_format(gles=False)) context.create() assert not context.isOpenGLES(), "We need glGetTexImage from OpenGL" self.size = size # Create offscreen surface with initialized format surface = QOffscreenSurface() surface.setFormat(context.format()) surface.create() self.ctx = RenderContext(context, surface) # Set up quick rendering self._control = control = QQuickRenderControl() self._window = window = QQuickWindow(control) self._cursor = self._window.cursor() # Don't polish/sync/render immediately for better performance, use a timer self._renderTimer = renderTimer = QTimer() renderTimer.setSingleShot(True) renderTimer.setInterval(5) renderTimer.timeout.connect(self._onRenderTimer) self._syncTimer = syncTimer = QTimer() syncTimer.setSingleShot(True) syncTimer.setInterval(5) syncTimer.timeout.connect(self._onSyncTimer) syncTimer.destroyed.connect(self._onSyncTimerDestroyed) # Request to create frame buffer window.sceneGraphInitialized.connect(self._onSceneGraphInitialized) # Request to release frame buffer window.sceneGraphInvalidated.connect(self._onSceneGraphInvalidated) # Only render is needed control.renderRequested.connect(self._onRenderRequested) # Polish, sync & render control.sceneChanged.connect(self._onSceneChanged) self.initialized = True # Attach root item self.rootItem.setParentItem(self._window.contentItem()) self._window.contentItem().forceActiveFocus() self._updateSizes() self.ctx.makeCurrent() self._control.initialize(self.ctx.glContext)
def initialize(self, size: QSize, shareContext: QOpenGLContext) -> None: """ Initialize offscreen renderer. Args: size: The size of the area available for rendering. shareContext: OpenGL context used as a share context. Raises: RuntimeError: If the renderer has already been initialized. """ print(f'QmlOffscreenRenderer.initialize: {size}') if self.initialized: raise RuntimeError('Already initialized') format = QSurfaceFormat() format.setDepthBufferSize(16) format.setStencilBufferSize(8) context = QOpenGLContext() context.setFormat(format) context.setShareContext(shareContext) context.create() self.size = size self.context = context # Create offscreen surface with initialized format self._surface = surface = QOffscreenSurface() surface.setFormat(context.format()) surface.create() # Set up quick rendering self._control = control = QQuickRenderControl() self._window = window = QQuickWindow(control) self._engine = engine = QQmlEngine() if not engine.incubationController(): engine.setIncubationController(window.incubationController()) # Don't polish/sync/render immediately for better performance, use a timer self._renderTimer = renderTimer = QTimer() renderTimer.setSingleShot(True) renderTimer.setInterval(5) renderTimer.timeout.connect(self._onRenderTimer) self._syncTimer = syncTimer = QTimer() syncTimer.setSingleShot(True) syncTimer.setInterval(5) syncTimer.timeout.connect(self._onSyncTimer) syncTimer.destroyed.connect(self._onSyncTimerDestroyed) # Request to create frame buffer window.sceneGraphInitialized.connect(self._onSceneGraphInitialized) # Request to release frame buffer window.sceneGraphInvalidated.connect(self._onSceneGraphInvalidated) # Only render is needed control.renderRequested.connect(self._onRenderRequested) # Polish, sync & render control.sceneChanged.connect(self._onSceneChanged) self.initialized = True # Load QML component self._component = component = QQmlComponent(self._engine, self.qmlUrl) if component.isLoading(): component.statusChanged.connect(self._onComponentStatusChanged) else: self._attachRootItem()