# GPU Off-Screen Buffer (gpu.offscreen)

This module provides access to offscreen rendering functions.

    # Draws an off-screen buffer and display it in the corner of the view.
    import bpy
    from bgl import *

    class OffScreenDraw(bpy.types.Operator):
        bl_idname = "view3d.offscreen_draw"
        bl_label = "View3D Offscreen Draw"

        _handle_calc = None
        _handle_draw = None
        is_enabled = False

        # manage draw handler
        @staticmethod
        def draw_callback_px(self, context):
            scene = context.scene
            aspect_ratio = scene.render.resolution_x / scene.render.resolution_y

            self._update_offscreen(context, self._offscreen)
            self._opengl_draw(context, self._texture, aspect_ratio, 0.2)

        @staticmethod
        def handle_add(self, context):
            OffScreenDraw._handle_draw = bpy.types.SpaceView3D.draw_handler_add(
                    self.draw_callback_px, (self, context),
                    'WINDOW', 'POST_PIXEL',
                    )

        @staticmethod
        def handle_remove():
            if OffScreenDraw._handle_draw is not None:
                bpy.types.SpaceView3D.draw_handler_remove(OffScreenDraw._handle_draw, 'WINDOW')

            OffScreenDraw._handle_draw = None

        # off-screen buffer
        @staticmethod
        def _setup_offscreen(context):
            import gpu
            scene = context.scene
            aspect_ratio = scene.render.resolution_x / scene.render.resolution_y

            try:
                offscreen = gpu.offscreen.new(512, int(512 / aspect_ratio))
            except Exception as e:
                print(e)
                offscreen = None

            return offscreen

        @staticmethod
        def _update_offscreen(context, offscreen):
            scene = context.scene
            render = scene.render
            camera = scene.camera

            modelview_matrix = camera.matrix_world.inverted()
            projection_matrix = camera.calc_matrix_camera(
                    render.resolution_x,
                    render.resolution_y,
                    render.pixel_aspect_x,
                    render.pixel_aspect_y,
                    )

            offscreen.draw_view3d(
                    scene,
                    context.space_data,
                    context.region,
                    projection_matrix,
                    modelview_matrix,
                    )

        @staticmethod
        def _opengl_draw(context, texture, aspect_ratio, scale):
            """
            OpenGL code to draw a rectangle in the viewport
            """

            glDisable(GL_DEPTH_TEST)

            # view setup
            glMatrixMode(GL_PROJECTION)
            glPushMatrix()
            glLoadIdentity()

            glMatrixMode(GL_MODELVIEW)
            glPushMatrix()
            glLoadIdentity()

            glOrtho(-1, 1, -1, 1, -15, 15)
            gluLookAt(0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)

            act_tex = Buffer(GL_INT, 1)
            glGetIntegerv(GL_TEXTURE_2D, act_tex)

            viewport = Buffer(GL_INT, 4)
            glGetIntegerv(GL_VIEWPORT, viewport)

            width = int(scale * viewport[2])
            height = int(width / aspect_ratio)

            glViewport(viewport[0], viewport[1], width, height)
            glScissor(viewport[0], viewport[1], width, height)

            # draw routine
            glEnable(GL_TEXTURE_2D)
            glActiveTexture(GL_TEXTURE0)

            glBindTexture(GL_TEXTURE_2D, texture)

            texco = [(1, 1), (0, 1), (0, 0), (1, 0)]
            verco = [(1.0, 1.0), (-1.0, 1.0), (-1.0, -1.0), (1.0, -1.0)]

            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)

            glColor4f(1.0, 1.0, 1.0, 1.0)

            glBegin(GL_QUADS)
            for i in range(4):
                glTexCoord3f(texco[i][0], texco[i][1], 0.0)
                glVertex2f(verco[i][0], verco[i][1])
            glEnd()

            # restoring settings
            glBindTexture(GL_TEXTURE_2D, act_tex[0])

            glDisable(GL_TEXTURE_2D)

            # reset view
            glMatrixMode(GL_PROJECTION)
            glPopMatrix()

            glMatrixMode(GL_MODELVIEW)
            glPopMatrix()

            glViewport(viewport[0], viewport[1], viewport[2], viewport[3])
            glScissor(viewport[0], viewport[1], viewport[2], viewport[3])

        # operator functions
        @classmethod
        def poll(cls, context):
            return context.area.type == 'VIEW_3D'

        def modal(self, context, event):
            if context.area:
                context.area.tag_redraw()

            return {'PASS_THROUGH'}

        def invoke(self, context, event):
            if OffScreenDraw.is_enabled:
                self.cancel(context)

                return {'FINISHED'}

            else:
                self._offscreen = OffScreenDraw._setup_offscreen(context)
                if self._offscreen:
                    self._texture = self._offscreen.color_texture
                else:
                    self.report({'ERROR'}, "Error initializing offscreen buffer. More details in the console")
                    return {'CANCELLED'}

                OffScreenDraw.handle_add(self, context)
                OffScreenDraw.is_enabled = True

                if context.area:
                    context.area.tag_redraw()

                context.window_manager.modal_handler_add(self)
                return {'RUNNING_MODAL'}

        def cancel(self, context):
            OffScreenDraw.handle_remove()
            OffScreenDraw.is_enabled = False

            if context.area:
                context.area.tag_redraw()

    def register():
        bpy.utils.register_class(OffScreenDraw)

    def unregister():
        bpy.utils.unregister_class(OffScreenDraw)

    if __name__ == "__main__":
        register()

new(width, height, samples=0)

> Return a GPUOffScreen.

> param width: | Horizontal dimension of the buffer.
> type width: | int`
> param height: | Vertical dimension of the buffer.
> type height: | int`
> param samples: | OpenGL samples to use for MSAA or zero to disable.
> type samples: | int
> return: | Newly created off-screen buffer.
> rtype: | `gpu.GPUOffscreen`

class `gpu.offscreen.``GPUOffscreen`
`This object gives access to off screen buffers.`

  bind(save=True)

  > Bind the offscreen object.

  > param save: | save OpenGL current states.
  > type save: | bool

  draw_view3d(scene, view3d, region, modelview_matrix, projection_matrix)

  > Draw the 3d viewport in the offscreen object.

  > param scene: | Scene to draw.
  > type scene: | `bpy.types.Scene`
  > param view3d: | 3D View to get the drawing settings from.
  > type view3d: | `bpy.types.SpaceView3D`
  > param region: | Region of the 3D View.
  > type region: | `bpy.types.Region`
  > param modelview_matrix:
  > | ModelView Matrix.
  > type modelview_matrix:
  > | `mathutils.Matrix`
  > param projection_matrix:
  > | Projection Matrix.
  > type projection_matrix:
  > | `mathutils.Matrix`

  free()

  > Free the offscreen object The framebuffer, texture and render objects will no longer be accessible.

  unbind(restore=True)

  > Unbind the offscreen object.

  > param restore: | restore OpenGL previous states.
  > type restore: | bool

  `color_texture`

    Color texture.

    Type: | int

  `height`

    Texture height.

    Type: | int

  `width`

    Texture width.

    Type: | int