mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-26 03:38:55 +01:00
restorable: Add comments
This commit is contained in:
parent
b51d93a707
commit
80940f9070
@ -75,7 +75,7 @@ func (c *graphicsContext) SetSize(screenWidth, screenHeight int, screenScale flo
|
|||||||
|
|
||||||
func (c *graphicsContext) initializeIfNeeded() error {
|
func (c *graphicsContext) initializeIfNeeded() error {
|
||||||
if !c.initialized {
|
if !c.initialized {
|
||||||
if err := restorable.ResetGLState(); err != nil {
|
if err := restorable.InitializeGLState(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.initialized = true
|
c.initialized = true
|
||||||
@ -113,7 +113,7 @@ func (c *graphicsContext) Update(updateCount int) error {
|
|||||||
_ = c.screen.Clear()
|
_ = c.screen.Clear()
|
||||||
drawWithFittingScale(c.screen, c.offscreen2)
|
drawWithFittingScale(c.screen, c.offscreen2)
|
||||||
|
|
||||||
if err := restorable.FlushAndResolveStalePixels(); err != nil {
|
if err := restorable.ResolveStaleImages(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -28,7 +28,7 @@ import (
|
|||||||
// Basically CopyImage just calls draw.Draw.
|
// Basically CopyImage just calls draw.Draw.
|
||||||
// If origImg is a paletted image, an optimized copying method is used.
|
// If origImg is a paletted image, an optimized copying method is used.
|
||||||
//
|
//
|
||||||
// CopyImage is used only from ebiten package but defined in restorable package,
|
// CopyImage is used only from ebiten package but defined in restorable package
|
||||||
// because this function needs to be tested but cannot be exposed to Ebiten users.
|
// because this function needs to be tested but cannot be exposed to Ebiten users.
|
||||||
func CopyImage(origImg image.Image) *image.RGBA {
|
func CopyImage(origImg image.Image) *image.RGBA {
|
||||||
size := origImg.Bounds().Size()
|
size := origImg.Bounds().Size()
|
||||||
|
@ -47,7 +47,8 @@
|
|||||||
// After any of the drawing functions is called, the target image can't be depended on by
|
// After any of the drawing functions is called, the target image can't be depended on by
|
||||||
// any other images. For example, if an image A depends on an image B, and B is changed
|
// any other images. For example, if an image A depends on an image B, and B is changed
|
||||||
// by a Fill call after that, the image A can't depend on the image B any more.
|
// by a Fill call after that, the image A can't depend on the image B any more.
|
||||||
// In this case, as the image A is no longer relaiable, the image A becomes 'stale'.
|
// In this case, as the image B can no longer be used to restore the image A,
|
||||||
|
// the image A becomes 'stale'.
|
||||||
// As all the stale images are resolved before context lost happens,
|
// As all the stale images are resolved before context lost happens,
|
||||||
// draw image history items are kept as they are
|
// draw image history items are kept as they are
|
||||||
// (even if an image C depends on the stale image A, it is still fine).
|
// (even if an image C depends on the stale image A, it is still fine).
|
||||||
|
@ -26,12 +26,15 @@ import (
|
|||||||
"github.com/hajimehoshi/ebiten/internal/opengl"
|
"github.com/hajimehoshi/ebiten/internal/opengl"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// MaxImageSize represents the maximum width/height of an image.
|
||||||
const MaxImageSize = graphics.MaxImageSize
|
const MaxImageSize = graphics.MaxImageSize
|
||||||
|
|
||||||
|
// QuadVertexSizeInBytes returns the byte size of vertices for a quadrilateral.
|
||||||
func QuadVertexSizeInBytes() int {
|
func QuadVertexSizeInBytes() int {
|
||||||
return graphics.QuadVertexSizeInBytes()
|
return graphics.QuadVertexSizeInBytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// drawImageHistoryItem is an item for history of draw-image commands.
|
||||||
type drawImageHistoryItem struct {
|
type drawImageHistoryItem struct {
|
||||||
image *Image
|
image *Image
|
||||||
vertices []float32
|
vertices []float32
|
||||||
@ -39,6 +42,8 @@ type drawImageHistoryItem struct {
|
|||||||
mode opengl.CompositeMode
|
mode opengl.CompositeMode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// canMerge returns a boolean value indicating whether the drawImageHistoryItem d
|
||||||
|
// can be merged with the given conditions.
|
||||||
func (d *drawImageHistoryItem) canMerge(image *Image, colorm *affine.ColorM, mode opengl.CompositeMode) bool {
|
func (d *drawImageHistoryItem) canMerge(image *Image, colorm *affine.ColorM, mode opengl.CompositeMode) bool {
|
||||||
if d.image != image {
|
if d.image != image {
|
||||||
return false
|
return false
|
||||||
@ -75,6 +80,7 @@ type Image struct {
|
|||||||
offsetY float64
|
offsetY float64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewImage creates an empty image with the given size and filter.
|
||||||
func NewImage(width, height int, filter opengl.Filter, volatile bool) *Image {
|
func NewImage(width, height int, filter opengl.Filter, volatile bool) *Image {
|
||||||
i := &Image{
|
i := &Image{
|
||||||
image: graphics.NewImage(width, height, filter),
|
image: graphics.NewImage(width, height, filter),
|
||||||
@ -86,6 +92,7 @@ func NewImage(width, height int, filter opengl.Filter, volatile bool) *Image {
|
|||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewImageFromImage creates an image with source image.
|
||||||
func NewImageFromImage(source *image.RGBA, width, height int, filter opengl.Filter) *Image {
|
func NewImageFromImage(source *image.RGBA, width, height int, filter opengl.Filter) *Image {
|
||||||
w2, h2 := math.NextPowerOf2Int(width), math.NextPowerOf2Int(height)
|
w2, h2 := math.NextPowerOf2Int(width), math.NextPowerOf2Int(height)
|
||||||
p := make([]uint8, 4*w2*h2)
|
p := make([]uint8, 4*w2*h2)
|
||||||
@ -102,6 +109,7 @@ func NewImageFromImage(source *image.RGBA, width, height int, filter opengl.Filt
|
|||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewScreenFramebufferImage creates a special image that framebuffer is one for the screen.
|
||||||
func NewScreenFramebufferImage(width, height int, offsetX, offsetY float64) *Image {
|
func NewScreenFramebufferImage(width, height int, offsetX, offsetY float64) *Image {
|
||||||
i := &Image{
|
i := &Image{
|
||||||
image: graphics.NewScreenFramebufferImage(width, height, offsetX, offsetY),
|
image: graphics.NewScreenFramebufferImage(width, height, offsetX, offsetY),
|
||||||
@ -115,14 +123,17 @@ func NewScreenFramebufferImage(width, height int, offsetX, offsetY float64) *Ima
|
|||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BasePixelsForTesting returns the image's basePixels for testing.
|
||||||
func (p *Image) BasePixelsForTesting() []uint8 {
|
func (p *Image) BasePixelsForTesting() []uint8 {
|
||||||
return p.basePixels
|
return p.basePixels
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Size returns the image's size.
|
||||||
func (p *Image) Size() (int, int) {
|
func (p *Image) Size() (int, int) {
|
||||||
return p.image.Size()
|
return p.image.Size()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// makeStale makes the image stale.
|
||||||
func (p *Image) makeStale() {
|
func (p *Image) makeStale() {
|
||||||
p.basePixels = nil
|
p.basePixels = nil
|
||||||
p.baseColor = color.RGBA{}
|
p.baseColor = color.RGBA{}
|
||||||
@ -130,6 +141,7 @@ func (p *Image) makeStale() {
|
|||||||
p.stale = true
|
p.stale = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clearIfVolatile clears the image if the image is volatile.
|
||||||
func (p *Image) clearIfVolatile() {
|
func (p *Image) clearIfVolatile() {
|
||||||
if !p.volatile {
|
if !p.volatile {
|
||||||
return
|
return
|
||||||
@ -144,8 +156,9 @@ func (p *Image) clearIfVolatile() {
|
|||||||
p.image.Fill(0, 0, 0, 0)
|
p.image.Fill(0, 0, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fill fills the image with the given color.
|
||||||
func (p *Image) Fill(r, g, b, a uint8) {
|
func (p *Image) Fill(r, g, b, a uint8) {
|
||||||
theImages.resetPixelsIfDependingOn(p)
|
theImages.makeStaleIfDependingOn(p)
|
||||||
p.basePixels = nil
|
p.basePixels = nil
|
||||||
p.baseColor = color.RGBA{r, g, b, a}
|
p.baseColor = color.RGBA{r, g, b, a}
|
||||||
p.drawImageHistory = nil
|
p.drawImageHistory = nil
|
||||||
@ -153,8 +166,9 @@ func (p *Image) Fill(r, g, b, a uint8) {
|
|||||||
p.image.Fill(r, g, b, a)
|
p.image.Fill(r, g, b, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReplacePixels replaces the image pixels with the given pixels slice.
|
||||||
func (p *Image) ReplacePixels(pixels []uint8) {
|
func (p *Image) ReplacePixels(pixels []uint8) {
|
||||||
theImages.resetPixelsIfDependingOn(p)
|
theImages.makeStaleIfDependingOn(p)
|
||||||
p.image.ReplacePixels(pixels)
|
p.image.ReplacePixels(pixels)
|
||||||
p.basePixels = pixels
|
p.basePixels = pixels
|
||||||
p.baseColor = color.RGBA{}
|
p.baseColor = color.RGBA{}
|
||||||
@ -162,8 +176,9 @@ func (p *Image) ReplacePixels(pixels []uint8) {
|
|||||||
p.stale = false
|
p.stale = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DrawImage draws a given image img to the image.
|
||||||
func (p *Image) DrawImage(img *Image, vertices []float32, colorm *affine.ColorM, mode opengl.CompositeMode) {
|
func (p *Image) DrawImage(img *Image, vertices []float32, colorm *affine.ColorM, mode opengl.CompositeMode) {
|
||||||
theImages.resetPixelsIfDependingOn(p)
|
theImages.makeStaleIfDependingOn(p)
|
||||||
if img.stale || img.volatile || !IsRestoringEnabled() {
|
if img.stale || img.volatile || !IsRestoringEnabled() {
|
||||||
p.makeStale()
|
p.makeStale()
|
||||||
} else {
|
} else {
|
||||||
@ -172,6 +187,7 @@ func (p *Image) DrawImage(img *Image, vertices []float32, colorm *affine.ColorM,
|
|||||||
p.image.DrawImage(img.image, vertices, colorm, mode)
|
p.image.DrawImage(img.image, vertices, colorm, mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// appendDrawImageHistory appends a draw-image history item to the image.
|
||||||
func (p *Image) appendDrawImageHistory(image *Image, vertices []float32, colorm *affine.ColorM, mode opengl.CompositeMode) {
|
func (p *Image) appendDrawImageHistory(image *Image, vertices []float32, colorm *affine.ColorM, mode opengl.CompositeMode) {
|
||||||
if p.stale || p.volatile {
|
if p.stale || p.volatile {
|
||||||
return
|
return
|
||||||
@ -218,6 +234,7 @@ func (p *Image) At(x, y int) (color.RGBA, error) {
|
|||||||
return color.RGBA{r, g, b, a}, nil
|
return color.RGBA{r, g, b, a}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// makeStaleIfDependingOn makes the image stale if the image depends on target.
|
||||||
func (p *Image) makeStaleIfDependingOn(target *Image) {
|
func (p *Image) makeStaleIfDependingOn(target *Image) {
|
||||||
if p.stale {
|
if p.stale {
|
||||||
return
|
return
|
||||||
@ -227,6 +244,7 @@ func (p *Image) makeStaleIfDependingOn(target *Image) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// readPixelsFromGPU reads the pixels from GPU and resolves the image's 'stale' state.
|
||||||
func (p *Image) readPixelsFromGPU(image *graphics.Image) error {
|
func (p *Image) readPixelsFromGPU(image *graphics.Image) error {
|
||||||
var err error
|
var err error
|
||||||
p.basePixels, err = image.Pixels()
|
p.basePixels, err = image.Pixels()
|
||||||
@ -239,7 +257,8 @@ func (p *Image) readPixelsFromGPU(image *graphics.Image) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Image) resolveStalePixels() error {
|
// resolveStale resolves the image's 'stale' state.
|
||||||
|
func (p *Image) resolveStale() error {
|
||||||
if !IsRestoringEnabled() {
|
if !IsRestoringEnabled() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -252,6 +271,7 @@ func (p *Image) resolveStalePixels() error {
|
|||||||
return p.readPixelsFromGPU(p.image)
|
return p.readPixelsFromGPU(p.image)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dependsOn returns a boolean value indicating whether the image depends on target.
|
||||||
func (p *Image) dependsOn(target *Image) bool {
|
func (p *Image) dependsOn(target *Image) bool {
|
||||||
for _, c := range p.drawImageHistory {
|
for _, c := range p.drawImageHistory {
|
||||||
if c.image == target {
|
if c.image == target {
|
||||||
@ -261,6 +281,7 @@ func (p *Image) dependsOn(target *Image) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dependingImages returns all images that is depended by the image.
|
||||||
func (p *Image) dependingImages() map[*Image]struct{} {
|
func (p *Image) dependingImages() map[*Image]struct{} {
|
||||||
r := map[*Image]struct{}{}
|
r := map[*Image]struct{}{}
|
||||||
for _, c := range p.drawImageHistory {
|
for _, c := range p.drawImageHistory {
|
||||||
@ -269,6 +290,7 @@ func (p *Image) dependingImages() map[*Image]struct{} {
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hasDependency returns a boolean value indicating whether the image depends on another image.
|
||||||
func (p *Image) hasDependency() bool {
|
func (p *Image) hasDependency() bool {
|
||||||
if p.stale {
|
if p.stale {
|
||||||
return false
|
return false
|
||||||
@ -335,8 +357,11 @@ func (p *Image) restore() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dispose disposes the image.
|
||||||
|
//
|
||||||
|
// After disposing, calling the funciton of the image causes unexpected results.
|
||||||
func (p *Image) Dispose() {
|
func (p *Image) Dispose() {
|
||||||
theImages.resetPixelsIfDependingOn(p)
|
theImages.makeStaleIfDependingOn(p)
|
||||||
p.image.Dispose()
|
p.image.Dispose()
|
||||||
p.image = nil
|
p.image = nil
|
||||||
p.basePixels = nil
|
p.basePixels = nil
|
||||||
@ -347,6 +372,9 @@ func (p *Image) Dispose() {
|
|||||||
runtime.SetFinalizer(p, nil)
|
runtime.SetFinalizer(p, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsInvalidated returns a boolean value indicating whether the image is invalidated.
|
||||||
|
//
|
||||||
|
// If an image is invalidated, GL context is lost and all the images should be restored asap.
|
||||||
func (p *Image) IsInvalidated() (bool, error) {
|
func (p *Image) IsInvalidated() (bool, error) {
|
||||||
// FlushCommands is required because c.offscreen.impl might not have an actual texture.
|
// FlushCommands is required because c.offscreen.impl might not have an actual texture.
|
||||||
if err := graphics.FlushCommands(); err != nil {
|
if err := graphics.FlushCommands(); err != nil {
|
||||||
|
@ -20,7 +20,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// restoringEnabled indicates if restoring happens or not.
|
// restoringEnabled indicates if restoring happens or not.
|
||||||
var restoringEnabled = true // This value is overridden at enabled_*.go.
|
//
|
||||||
|
// This value is overridden at enabled_*.go.
|
||||||
|
var restoringEnabled = true
|
||||||
|
|
||||||
// IsRestoringEnabled returns a boolean value indicating whether
|
// IsRestoringEnabled returns a boolean value indicating whether
|
||||||
// restoring process works or not.
|
// restoring process works or not.
|
||||||
@ -37,24 +39,30 @@ func EnableRestoringForTesting() {
|
|||||||
|
|
||||||
// images is a set of Image objects.
|
// images is a set of Image objects.
|
||||||
type images struct {
|
type images struct {
|
||||||
images map[*Image]struct{}
|
images map[*Image]struct{}
|
||||||
lastChecked *Image
|
lastTarget *Image
|
||||||
m sync.Mutex
|
m sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// theImages represents the images for the current process.
|
||||||
var theImages = &images{
|
var theImages = &images{
|
||||||
images: map[*Image]struct{}{},
|
images: map[*Image]struct{}{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// FlushAndResolveStalePixels flushes the queued draw commands and resolves
|
// ResolveStaleImages flushes the queued draw commands and resolves
|
||||||
// all stale images.
|
// all stale images.
|
||||||
func FlushAndResolveStalePixels() error {
|
//
|
||||||
|
// ResolveStaleImages is intended to be called at the end of a frame.
|
||||||
|
func ResolveStaleImages() error {
|
||||||
if err := graphics.FlushCommands(); err != nil {
|
if err := graphics.FlushCommands(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return theImages.resolveStalePixels()
|
return theImages.resolveStaleImages()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore restores the images.
|
||||||
|
//
|
||||||
|
// Restoring means to make all *graphics.Image objects have their textures and framebuffers.
|
||||||
func Restore() error {
|
func Restore() error {
|
||||||
if err := graphics.ResetGLState(); err != nil {
|
if err := graphics.ResetGLState(); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -62,35 +70,45 @@ func Restore() error {
|
|||||||
return theImages.restore()
|
return theImages.restore()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ClearVolatileImages clears volatile images.
|
||||||
|
//
|
||||||
|
// ClearVolatileImages is intended to be called at the start of a frame.
|
||||||
func ClearVolatileImages() {
|
func ClearVolatileImages() {
|
||||||
theImages.clearVolatileImages()
|
theImages.clearVolatileImages()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add adds img to the images.
|
||||||
func (i *images) add(img *Image) {
|
func (i *images) add(img *Image) {
|
||||||
i.m.Lock()
|
i.m.Lock()
|
||||||
defer i.m.Unlock()
|
defer i.m.Unlock()
|
||||||
i.images[img] = struct{}{}
|
i.images[img] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove removes img from the images.
|
||||||
func (i *images) remove(img *Image) {
|
func (i *images) remove(img *Image) {
|
||||||
i.m.Lock()
|
i.m.Lock()
|
||||||
defer i.m.Unlock()
|
defer i.m.Unlock()
|
||||||
delete(i.images, img)
|
delete(i.images, img)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *images) resolveStalePixels() error {
|
// resolveStaleImages resolves stale images.
|
||||||
|
func (i *images) resolveStaleImages() error {
|
||||||
i.m.Lock()
|
i.m.Lock()
|
||||||
defer i.m.Unlock()
|
defer i.m.Unlock()
|
||||||
i.lastChecked = nil
|
i.lastTarget = nil
|
||||||
for img := range i.images {
|
for img := range i.images {
|
||||||
if err := img.resolveStalePixels(); err != nil {
|
if err := img.resolveStale(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *images) resetPixelsIfDependingOn(target *Image) {
|
// makeStaleIfDependingOn makes all the images stale that depend on target.
|
||||||
|
//
|
||||||
|
// When target is changed, all images depending on target can't be restored with target.
|
||||||
|
// makeStaleIfDependingOn is called in such situation.
|
||||||
|
func (i *images) makeStaleIfDependingOn(target *Image) {
|
||||||
// Avoid defer for performance
|
// Avoid defer for performance
|
||||||
i.m.Lock()
|
i.m.Lock()
|
||||||
if target == nil {
|
if target == nil {
|
||||||
@ -98,11 +116,11 @@ func (i *images) resetPixelsIfDependingOn(target *Image) {
|
|||||||
i.m.Unlock()
|
i.m.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if i.lastChecked == target {
|
if i.lastTarget == target {
|
||||||
i.m.Unlock()
|
i.m.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i.lastChecked = target
|
i.lastTarget = target
|
||||||
for img := range i.images {
|
for img := range i.images {
|
||||||
// TODO: This seems not enough: What if img becomes stale but what about
|
// TODO: This seems not enough: What if img becomes stale but what about
|
||||||
// other images depend on img? (#357)
|
// other images depend on img? (#357)
|
||||||
@ -111,17 +129,21 @@ func (i *images) resetPixelsIfDependingOn(target *Image) {
|
|||||||
i.m.Unlock()
|
i.m.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// restore restores the images.
|
||||||
|
//
|
||||||
|
// Restoring means to make all *graphics.Image objects have their textures and framebuffers.
|
||||||
func (i *images) restore() error {
|
func (i *images) restore() error {
|
||||||
i.m.Lock()
|
i.m.Lock()
|
||||||
defer i.m.Unlock()
|
defer i.m.Unlock()
|
||||||
if !IsRestoringEnabled() {
|
if !IsRestoringEnabled() {
|
||||||
panic("not reached")
|
panic("not reached")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Framebuffers/textures cannot be disposed since framebuffers/textures that
|
// Framebuffers/textures cannot be disposed since framebuffers/textures that
|
||||||
// don't belong to the current context.
|
// don't belong to the current context.
|
||||||
|
|
||||||
// Let's do topological sort based on dependencies of drawing history.
|
// Let's do topological sort based on dependencies of drawing history.
|
||||||
// There should not be a loop since cyclic drawing makes images stale.
|
// It is assured that there are not loops since cyclic drawing makes images stale.
|
||||||
type edge struct {
|
type edge struct {
|
||||||
source *Image
|
source *Image
|
||||||
target *Image
|
target *Image
|
||||||
@ -170,6 +192,7 @@ func (i *images) restore() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clearVolatileImages clears the volatile images.
|
||||||
func (i *images) clearVolatileImages() {
|
func (i *images) clearVolatileImages() {
|
||||||
i.m.Lock()
|
i.m.Lock()
|
||||||
defer i.m.Unlock()
|
defer i.m.Unlock()
|
||||||
@ -178,6 +201,7 @@ func (i *images) clearVolatileImages() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ResetGLState() error {
|
// InitializeGLState initializes the GL state.
|
||||||
|
func InitializeGLState() error {
|
||||||
return graphics.ResetGLState()
|
return graphics.ResetGLState()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user