veandco / go-sdl2

SDL2 binding for Go
https://godoc.org/github.com/veandco/go-sdl2
BSD 3-Clause "New" or "Revised" License
2.2k stars 218 forks source link

Window stalls after 2nd texture.Update #363

Closed 5k3105 closed 5 years ago

5k3105 commented 5 years ago

Win7. All other SDL examples work. Window becomes inactive after second render, but program continues to print:

λ .\testsdl5.exe
texture:  1
texture:  2
texture:  3
texture:  4
package main

import (
    "fmt"
    "github.com/veandco/go-sdl2/sdl"
    "os"
    "runtime"
    "unsafe"
)

const (
    winTitle            string = "2 textures?"
    VisibleScreenWidth  int32  = 403
    VisibleScreenHeight int32  = 284
    cols                       = VisibleScreenWidth
    rows                       = VisibleScreenHeight
    sizeof_uint32              = 4
    m                          = 3
)

var (
    renderer      *sdl.Renderer
    texture       *sdl.Texture
    frame         [rows * cols]uint32
    color_palette [16]uint32
    format        *sdl.PixelFormat
)

func main() {
    runtime.LockOSThread()

    var err error
    if err = sdl.Init(sdl.INIT_EVERYTHING); err != nil {
        fmt.Fprintf(os.Stderr, "Failed to initialize SDL: %s\n", err)
        os.Exit(1)
    }
    defer sdl.Quit()

    var window *sdl.Window
    if window, err = sdl.CreateWindow(winTitle, sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, VisibleScreenWidth*m, VisibleScreenHeight*m, sdl.WINDOW_SHOWN); err != nil {
        fmt.Fprintf(os.Stderr, "Failed to create window: %s\n", err)
        os.Exit(2)
    }
    defer window.Destroy()

    if renderer, err = sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED); err != nil {
        fmt.Fprintf(os.Stderr, "Failed to create renderer: %s\n", err)
        os.Exit(2)
    }
    renderer.Clear()
    defer renderer.Destroy()

    texture, err = renderer.CreateTexture(sdl.PIXELFORMAT_ARGB8888, sdl.TEXTUREACCESS_STREAMING, cols, rows)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Failed to create texture: %s\n", err)
        os.Exit(2)
    }
    defer texture.Destroy()

    format, err = sdl.AllocFormat(sdl.PIXELFORMAT_ARGB8888)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Failed to create format: %s\n", err)
        os.Exit(2)
    }

    color_palette = init_color_palette(format)
    frame = [rows * cols]uint32{}

    for i := 1; i < 5; i++ {
        println("texture: ", i)

        screen_draw_rect(10+i, 10+i, 60, i)

        texture.Update(nil, (*[sizeof_uint32]byte)(unsafe.Pointer(&frame))[:], int(cols)*sizeof_uint32)
        renderer.Clear()
        renderer.Copy(texture, nil, nil)
        renderer.Present()

        sdl.Delay(3000)
    }

}

func screen_draw_rect(x, y, n, color int) {
    for i := 0; i <= n; i++ {
        screen_update_pixel(x+i, y, color)
        screen_update_pixel(x, y+i, color)
        screen_update_pixel(x+i, y+n, color)
        screen_update_pixel(x+n, y+i, color)
    }
}

func screen_update_pixel(x, y, color int) {
    frame[y*int(cols)+x] = color_palette[color&0xf]
}

func init_color_palette(format_ *sdl.PixelFormat) [16]uint32 {
    color_palette := [16]uint32{}
    color_palette[0] = sdl.MapRGB(format_, 0x00, 0x00, 0x00)  /// black
    color_palette[1] = sdl.MapRGB(format_, 0xff, 0xff, 0xff)  /// white
    color_palette[2] = sdl.MapRGB(format_, 0xab, 0x31, 0x26)  /// red
    color_palette[3] = sdl.MapRGB(format_, 0x66, 0xda, 0xff)  /// cyan
    color_palette[4] = sdl.MapRGB(format_, 0xbb, 0x3f, 0xb8)  /// violet/purple
    color_palette[5] = sdl.MapRGB(format_, 0x55, 0xce, 0x58)  /// green
    color_palette[6] = sdl.MapRGB(format_, 0x1d, 0x0e, 0x97)  /// blue
    color_palette[7] = sdl.MapRGB(format_, 0xea, 0xf5, 0x7c)  /// yellow
    color_palette[8] = sdl.MapRGB(format_, 0xb9, 0x74, 0x18)  /// orange
    color_palette[9] = sdl.MapRGB(format_, 0x78, 0x53, 0x00)  /// brown
    color_palette[10] = sdl.MapRGB(format_, 0xdd, 0x93, 0x87) /// lt red
    color_palette[11] = sdl.MapRGB(format_, 0x5b, 0x5b, 0x5b) /// dk grey
    color_palette[12] = sdl.MapRGB(format_, 0x8b, 0x8b, 0x8b) /// grey 2
    color_palette[13] = sdl.MapRGB(format_, 0xb0, 0xf4, 0xac) /// lt green
    color_palette[14] = sdl.MapRGB(format_, 0xaa, 0x9d, 0xef) /// lt blue
    color_palette[15] = sdl.MapRGB(format_, 0xb8, 0xb8, 0xb8) /// ly grey
    return color_palette
}
veeableful commented 5 years ago

Hi @5k3105, could you try this C counterpart to see if the same problem happens?

#include <SDL2/SDL.h>

#define winTitle "2 textures?"
#define VisibleScreenWidth (403)
#define VisibleScreenHeight (283)
#define rows (VisibleScreenWidth)
#define cols (VisibleScreenHeight)
#define sizeof_uint32 (4)
#define m (3)

static SDL_Renderer *renderer;
static SDL_Texture *texture;
static Uint32 frame[rows * cols];
static Uint32 color_palette[16];
static SDL_PixelFormat *format;

void screen_update_pixel(int x, int y, int color)
{
    frame[y*((int)(cols))+x] = color_palette[color&0xf];
}

void screen_draw_rect(int x, int y, int n, int color)
{
    int i;

    for (i = 0; i <= n; i++) {
        screen_update_pixel(x+i, y, color);
        screen_update_pixel(x, y+i, color);
        screen_update_pixel(x+i, y+n, color);
        screen_update_pixel(x+n, y+i, color);
    }
}

void init_color_palette(Uint32 *color_palette, SDL_PixelFormat *format_)
{
    color_palette[0] = SDL_MapRGB(format_, 0x00, 0x00, 0x00); /// black
    color_palette[1] = SDL_MapRGB(format_, 0xff, 0xff, 0xff); /// white
    color_palette[2] = SDL_MapRGB(format_, 0xab, 0x31, 0x26); /// red
    color_palette[3] = SDL_MapRGB(format_, 0x66, 0xda, 0xff); /// cyan
    color_palette[4] = SDL_MapRGB(format_, 0xbb, 0x3f, 0xb8); /// violet/purple
    color_palette[5] = SDL_MapRGB(format_, 0x55, 0xce, 0x58); /// green
    color_palette[6] = SDL_MapRGB(format_, 0x1d, 0x0e, 0x97); /// blue
    color_palette[7] = SDL_MapRGB(format_, 0xea, 0xf5, 0x7c); /// yellow
    color_palette[8] = SDL_MapRGB(format_, 0xb9, 0x74, 0x18); /// orange
    color_palette[9] = SDL_MapRGB(format_, 0x78, 0x53, 0x00); /// brown
    color_palette[10] = SDL_MapRGB(format_, 0xdd, 0x93, 0x87); /// lt red
    color_palette[11] = SDL_MapRGB(format_, 0x5b, 0x5b, 0x5b); /// dk grey
    color_palette[12] = SDL_MapRGB(format_, 0x8b, 0x8b, 0x8b); /// grey 2
    color_palette[13] = SDL_MapRGB(format_, 0xb0, 0xf4, 0xac); /// lt green
    color_palette[14] = SDL_MapRGB(format_, 0xaa, 0x9d, 0xef); /// lt blue
    color_palette[15] = SDL_MapRGB(format_, 0xb8, 0xb8, 0xb8); /// ly grey
}

int main()
{
    SDL_Window *window = NULL;
    int ret = 0;
    int i = 0;

    if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
        ret = 1;
        goto out;
    }

    window = SDL_CreateWindow(winTitle, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, VisibleScreenWidth * m, VisibleScreenHeight * m, SDL_WINDOW_SHOWN);
    if (!window) {
        fprintf(stderr, "%s\n", SDL_GetError());
        ret = 2;
        goto out;
    }

    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    if (!renderer) {
        fprintf(stderr, "%s\n", SDL_GetError());
        ret = 2;
        goto out;
    }

    texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, cols, rows);
    if (!texture) {
        fprintf(stderr, "%s\n", SDL_GetError());
        ret = 2;
        goto out;
    }

    format = SDL_AllocFormat(SDL_PIXELFORMAT_ARGB8888);
    if (!format) {
        fprintf(stderr, "%s\n", SDL_GetError());
        ret = 2;
        goto out;
    }

    init_color_palette(color_palette, format);

    for (i = 1; i < 5; i++) {
        fprintf(stdout, "texture: %d\n", i);

        screen_draw_rect(10 + i, 10 + i, 60, i);

        SDL_UpdateTexture(texture, NULL, frame, cols * sizeof_uint32);
        SDL_RenderClear(renderer);
        SDL_RenderCopy(renderer, texture, NULL, NULL);
        SDL_RenderPresent(renderer);
        SDL_Delay(3000);
    }   

out:
    if (texture) {
        SDL_DestroyTexture(texture);
    }
    if (renderer) {
        SDL_DestroyRenderer(renderer);
    }
    if (window) {
        SDL_DestroyWindow(window);
    }
    SDL_Quit();

    return ret;
}

I compiled and ran it with

gcc main.c -lSDL2
./a.out
5k3105 commented 5 years ago

Hi, thanks for getting back to me :)

This c code works the same as my go code example. It stalls after the second texture.

btw, for it to work I needed to define SDL_MAIN_HANDLED at the top:

#define SDL_MAIN_HANDLED
#include <SDL2/SDL.h>
veeableful commented 5 years ago

Hm.. I can't seem to reproduce it on my Windows 10 system.

The only thing I would try is to use Texture.Lock() and Texture.Unlock() which is recommended by the official wiki when updating streaming textures. It probably won't solve the problem but I guess it's worth a try.

You could also ask for more support in SDL's official forum here. My knowledge on SDL2 itself isn't deep enough to know what's going on :(

5k3105 commented 5 years ago

Hi,

putting a PollEvent inside the loop fixed it:

            sdl.Delay(300)

            for event = sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
                switch event.(type) {
                case *sdl.QuitEvent:
                    running = false
                }

            }

Thanks!