src/video/emscripten/SDL_emscriptenframebuffer.c
author Ryan C. Gordon
Mon, 23 Jan 2017 12:06:10 -0500
changeset 10837 c2f241c2f6ad
parent 10737 3406a0f8b041
child 11811 5d94cb6b24d3
permissions -rw-r--r--
audio: Fix same bug as last commit, but for _mm_bslli_si128 vs _mm_slli_si128.
icculus@9278
     1
/*
icculus@9278
     2
  Simple DirectMedia Layer
slouken@10737
     3
  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
icculus@9278
     4
icculus@9278
     5
  This software is provided 'as-is', without any express or implied
icculus@9278
     6
  warranty.  In no event will the authors be held liable for any damages
icculus@9278
     7
  arising from the use of this software.
icculus@9278
     8
icculus@9278
     9
  Permission is granted to anyone to use this software for any purpose,
icculus@9278
    10
  including commercial applications, and to alter it and redistribute it
icculus@9278
    11
  freely, subject to the following restrictions:
icculus@9278
    12
icculus@9278
    13
  1. The origin of this software must not be misrepresented; you must not
icculus@9278
    14
     claim that you wrote the original software. If you use this software
icculus@9278
    15
     in a product, an acknowledgment in the product documentation would be
icculus@9278
    16
     appreciated but is not required.
icculus@9278
    17
  2. Altered source versions must be plainly marked as such, and must not be
icculus@9278
    18
     misrepresented as being the original software.
icculus@9278
    19
  3. This notice may not be removed or altered from any source distribution.
icculus@9278
    20
*/
icculus@9278
    21
#include "../../SDL_internal.h"
icculus@9278
    22
icculus@9278
    23
#if SDL_VIDEO_DRIVER_EMSCRIPTEN
icculus@9278
    24
icculus@9278
    25
#include "SDL_emscriptenvideo.h"
icculus@9278
    26
#include "SDL_emscriptenframebuffer.h"
icculus@9278
    27
icculus@9278
    28
icculus@9278
    29
int Emscripten_CreateWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch)
icculus@9278
    30
{
icculus@9278
    31
    SDL_Surface *surface;
icculus@9278
    32
    const Uint32 surface_format = SDL_PIXELFORMAT_BGR888;
icculus@9278
    33
    int w, h;
icculus@9278
    34
    int bpp;
icculus@9278
    35
    Uint32 Rmask, Gmask, Bmask, Amask;
icculus@9278
    36
icculus@9278
    37
    /* Free the old framebuffer surface */
icculus@9278
    38
    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
icculus@9278
    39
    surface = data->surface;
icculus@9278
    40
    SDL_FreeSurface(surface);
icculus@9278
    41
icculus@9278
    42
    /* Create a new one */
icculus@9278
    43
    SDL_PixelFormatEnumToMasks(surface_format, &bpp, &Rmask, &Gmask, &Bmask, &Amask);
icculus@9278
    44
    SDL_GetWindowSize(window, &w, &h);
icculus@9278
    45
icculus@9278
    46
    surface = SDL_CreateRGBSurface(0, w, h, bpp, Rmask, Gmask, Bmask, Amask);
icculus@9278
    47
    if (!surface) {
icculus@9278
    48
        return -1;
icculus@9278
    49
    }
icculus@9278
    50
icculus@9278
    51
    /* Save the info and return! */
icculus@9278
    52
    data->surface = surface;
icculus@9278
    53
    *format = surface_format;
icculus@9278
    54
    *pixels = surface->pixels;
icculus@9278
    55
    *pitch = surface->pitch;
icculus@9278
    56
    return 0;
icculus@9278
    57
}
icculus@9278
    58
icculus@9278
    59
int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rect * rects, int numrects)
icculus@9278
    60
{
icculus@9278
    61
    SDL_Surface *surface;
icculus@9278
    62
icculus@9278
    63
    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
icculus@9278
    64
    surface = data->surface;
icculus@9278
    65
    if (!surface) {
philipp@9342
    66
        return SDL_SetError("Couldn't find framebuffer surface for window");
icculus@9278
    67
    }
icculus@9278
    68
icculus@9278
    69
    /* Send the data to the display */
icculus@9278
    70
icculus@9278
    71
    EM_ASM_INT({
alonzakai@10323
    72
        var w = $0;
alonzakai@10323
    73
        var h = $1;
alonzakai@10323
    74
        var pixels = $2;
icculus@9278
    75
alonzakai@10323
    76
        if (!Module['SDL2']) Module['SDL2'] = {};
alonzakai@10323
    77
        var SDL2 = Module['SDL2'];
alonzakai@10323
    78
        if (SDL2.ctxCanvas !== Module['canvas']) {
alonzakai@10336
    79
            SDL2.ctx = Module['createContext'](Module['canvas'], false, true);
alonzakai@10323
    80
            SDL2.ctxCanvas = Module['canvas'];
alonzakai@10323
    81
        }
alonzakai@10323
    82
        if (SDL2.w !== w || SDL2.h !== h || SDL2.imageCtx !== SDL2.ctx) {
alonzakai@10323
    83
            SDL2.image = SDL2.ctx.createImageData(w, h);
alonzakai@10323
    84
            SDL2.w = w;
alonzakai@10323
    85
            SDL2.h = h;
alonzakai@10323
    86
            SDL2.imageCtx = SDL2.ctx;
alonzakai@10323
    87
        }
alonzakai@10323
    88
        var data = SDL2.image.data;
alonzakai@10323
    89
        var src = pixels >> 2;
icculus@9278
    90
        var dst = 0;
icculus@9278
    91
        var num;
icculus@9278
    92
        if (typeof CanvasPixelArray !== 'undefined' && data instanceof CanvasPixelArray) {
icculus@9278
    93
            // IE10/IE11: ImageData objects are backed by the deprecated CanvasPixelArray,
icculus@9278
    94
            // not UInt8ClampedArray. These don't have buffers, so we need to revert
icculus@9278
    95
            // to copying a byte at a time. We do the undefined check because modern
icculus@9278
    96
            // browsers do not define CanvasPixelArray anymore.
icculus@9278
    97
            num = data.length;
icculus@9278
    98
            while (dst < num) {
icculus@9278
    99
                var val = HEAP32[src]; // This is optimized. Instead, we could do {{{ makeGetValue('buffer', 'dst', 'i32') }}};
icculus@9278
   100
                data[dst  ] = val & 0xff;
icculus@9278
   101
                data[dst+1] = (val >> 8) & 0xff;
icculus@9278
   102
                data[dst+2] = (val >> 16) & 0xff;
alonzakai@10323
   103
                data[dst+3] = 0xff;
icculus@9278
   104
                src++;
icculus@9278
   105
                dst += 4;
icculus@9278
   106
            }
icculus@9278
   107
        } else {
alonzakai@10323
   108
            if (SDL2.data32Data !== data) {
alonzakai@10323
   109
                SDL2.data32 = new Int32Array(data.buffer);
alonzakai@10323
   110
                SDL2.data8 = new Uint8Array(data.buffer);
alonzakai@10323
   111
            }
alonzakai@10323
   112
            var data32 = SDL2.data32;
icculus@9278
   113
            num = data32.length;
alonzakai@10323
   114
            // logically we need to do
alonzakai@10323
   115
            //      while (dst < num) {
alonzakai@10323
   116
            //          data32[dst++] = HEAP32[src++] | 0xff000000
alonzakai@10323
   117
            //      }
alonzakai@10323
   118
            // the following code is faster though, because
alonzakai@10323
   119
            // .set() is almost free - easily 10x faster due to
alonzakai@10323
   120
            // native memcpy efficiencies, and the remaining loop
alonzakai@10323
   121
            // just stores, not load + store, so it is faster
alonzakai@10323
   122
            data32.set(HEAP32.subarray(src, src + num));
alonzakai@10323
   123
            var data8 = SDL2.data8;
alonzakai@10323
   124
            var i = 3;
alonzakai@10323
   125
            var j = i + 4*num;
alonzakai@10323
   126
            if (num % 8 == 0) {
alonzakai@10323
   127
                // unrolling gives big speedups
alonzakai@10323
   128
                while (i < j) {
alonzakai@10323
   129
                  data8[i] = 0xff;
alonzakai@10323
   130
                  i = i + 4 | 0;
alonzakai@10323
   131
                  data8[i] = 0xff;
alonzakai@10323
   132
                  i = i + 4 | 0;
alonzakai@10323
   133
                  data8[i] = 0xff;
alonzakai@10323
   134
                  i = i + 4 | 0;
alonzakai@10323
   135
                  data8[i] = 0xff;
alonzakai@10323
   136
                  i = i + 4 | 0;
alonzakai@10323
   137
                  data8[i] = 0xff;
alonzakai@10323
   138
                  i = i + 4 | 0;
alonzakai@10323
   139
                  data8[i] = 0xff;
alonzakai@10323
   140
                  i = i + 4 | 0;
alonzakai@10323
   141
                  data8[i] = 0xff;
alonzakai@10323
   142
                  i = i + 4 | 0;
alonzakai@10323
   143
                  data8[i] = 0xff;
alonzakai@10323
   144
                  i = i + 4 | 0;
icculus@9278
   145
                }
alonzakai@10323
   146
             } else {
alonzakai@10323
   147
                while (i < j) {
alonzakai@10323
   148
                  data8[i] = 0xff;
alonzakai@10323
   149
                  i = i + 4 | 0;
icculus@9278
   150
                }
icculus@9278
   151
            }
icculus@9278
   152
        }
icculus@9278
   153
alonzakai@10323
   154
        SDL2.ctx.putImageData(SDL2.image, 0, 0);
icculus@9278
   155
        return 0;
icculus@9278
   156
    }, surface->w, surface->h, surface->pixels);
icculus@9278
   157
icculus@9278
   158
    /*if (SDL_getenv("SDL_VIDEO_Emscripten_SAVE_FRAMES")) {
icculus@9300
   159
        static int frame_number = 0;
icculus@9278
   160
        char file[128];
icculus@9278
   161
        SDL_snprintf(file, sizeof(file), "SDL_window%d-%8.8d.bmp",
icculus@9278
   162
                     SDL_GetWindowID(window), ++frame_number);
icculus@9278
   163
        SDL_SaveBMP(surface, file);
icculus@9278
   164
    }*/
icculus@9278
   165
    return 0;
icculus@9278
   166
}
icculus@9278
   167
icculus@9278
   168
void Emscripten_DestroyWindowFramebuffer(_THIS, SDL_Window * window)
icculus@9278
   169
{
icculus@9278
   170
    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
icculus@9278
   171
icculus@9278
   172
    SDL_FreeSurface(data->surface);
icculus@9278
   173
    data->surface = NULL;
icculus@9278
   174
}
icculus@9278
   175
icculus@9278
   176
#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */
icculus@9278
   177
icculus@9278
   178
/* vi: set ts=4 sw=4 expandtab: */