2
\$\begingroup\$

So I started using Awesomium, and I'm experiencing some difficulties.

I want to create a new type of Awesomium::Surface and implement it in my custom Awesomium::SurfaceFactory to render Awesomium::WebView->surface as SDL_Texture.

I'm currently stuck at the Paint function which is supposed to update some pixels, so I have this (in the project it's separated in header and definitions):

class AwsSurface {

    public:
    AwsSurface(int w, int h) : public Awesomium::Surface {
        // _renderer is my global renderer, on Awesomium DOCs it says that pixels are
        // "in 32-bit BGRA format" so I guess the format is right...
        texture = SDL_CreateTexture(
            _renderer, 
            SDL_PIXELFORMAT_BGRA8888, 
            SDL_TEXTUREACCESS_STREAMING, 
            w, 
            h
        );
        dst_rect = {0, 0, w, h};        
    }

    void Paint(unsigned char* src_buffer, 
             int src_row_span, 
             const Awesomium::Rect &src_rect, 
             const Awesomium::Rect &dest_rect) {
    }

    protected:
    SDL_Texture* texture;
    SDL_Rect dst_rect;
};

I'm not sure if I get it right, but fromwhat the DOCs say if I'm given a src_rect={2, 1, 2, 3} and src_row_span=20 I am in this situation, right?

Now, I understood how the buffer works (more or less), but I don't know how to copy the pixels from it onto my texture (in the given position).

Edit: I came up with this paint function:

void AwsSurface::Paint(unsigned char* src_buffer, 
                       int src_row_span, 
                       const aws::Rect &src_rect, 
                       const aws::Rect &dest_rect) {
    Uint32* src_buffer_i = (Uint32*)src_buffer;
    src_row_span /= 4;
    int dest_row_span;
    Uint32* dest_buffer;
    SDL_Rect r = AwsRectToSDL(dest_rect); // Custom function to convert the rect
    SDL_LockTexture(
        texture, 
        &r, 
        (void**)&dest_buffer, 
        &dest_row_span
    );
    dest_row_span /= 4;
    for (int x = 0; x < src_rect.width; x++) {
        for (int y = 0; y < src_rect.height; y++) {
            Uint32* s = src_buffer_i + (src_rect.y + y) * src_row_span + src_rect.x + x;
            Uint32* d = dest_buffer + (dest_rect.y + y) * dest_row_span + dest_rect.x + x;
            *d = *s; // Here happens the exception
        }
    }
    SDL_UnlockTexture(texture);
}

But I get an "access violation on writing" exception on the line above, this happens after some successful executions (usually 6/7) and every time on the same rectangle {0, 0, 466, 26}.

\$\endgroup\$
  • \$\begingroup\$ Possible duplicate of: stackoverflow.com/q/30626543 \$\endgroup\$ – Tyyppi_77 Jan 13 '16 at 7:55
  • \$\begingroup\$ @Tyyppi_77 That question has an answer only for surfaces, I'm looking for textures \$\endgroup\$ – Xriuk Jan 13 '16 at 14:51
  • \$\begingroup\$ Downvoters, care to explain? \$\endgroup\$ – Xriuk Jan 16 '16 at 8:08
  • \$\begingroup\$ Where is the access violation? What line? If you just memset the texture with the correct size calculation, say to 0xFF, does the problem happen still? Worth trying to isolate where the violation is from. \$\endgroup\$ – Steven Jan 19 '16 at 21:42
  • \$\begingroup\$ @Steven I marked the line in the code: it's *d = *s. As I said I encounter the violation only on a specific rect, the rects before that, are copied successfully. How can I memset from src_buffer_i to dest_buffer? \$\endgroup\$ – Xriuk Jan 20 '16 at 16:55
2
\$\begingroup\$

I didn't go with the way of implementing a custom Awesomium class for this. Instead I just updated data of a single texture by querying the surface from Awesomium.

// Gets the surface of the web view.
Awesomium::BitmapSurface* surface = static_cast<Awesomium::BitmapSurface*>(webView->surface());
if (surface != NULL)
{
    unsigned char* pixels = nullptr;
    int pitch = 0;

    // "pixels" now point to the pixels of the texture.
    if (SDL_LockTexture(texture, nullptr, (void**)&pixels, &pitch) != 0)
    {
        std::cout << SDL_GetError() << std::endl;
    }
    // Copies the pixels to the texture.
    surface->CopyTo(pixels, pitch, 4, true, false);
    SDL_UnlockTexture(texture);
}

This assumes that you already have created an SDL_Texture called texturewith the correct viewport size. Awesomium then offers an utility method CopyTo that you can use to put the pixel data to the texture.

You're right on the fact that the texture needs to be created with the SDL_PIXELFORMAT_ABGR8888 flag. I also used the SDL_TEXTUREACCESS_STREAMING flag on the texture.

Anyways I find that this approach is somewhat cleaner atleast for someone who's not familiar with Awesomium's class design, as it's mostly using SDL calls and then just a simple call to an Awesomium method.

After that you're just free to render your texture to the screen.

Oh, and if you would like to use the Awesomium custom class structure, I'm sure you can figure out how to adapt this example code to put into use there.

\$\endgroup\$
  • 1
    \$\begingroup\$ This would mean writing the entire texture everytime... Please see my edit to the question. \$\endgroup\$ – Xriuk Jan 13 '16 at 18:54
  • \$\begingroup\$ Is writing the entire texture a performance issue that you have tested out and found out to be an issue? It's better to only optimize when necessary. \$\endgroup\$ – Tyyppi_77 Jan 13 '16 at 19:31
  • 1
    \$\begingroup\$ No, but by implementing a class I can use Awesomium events, this way it will paint only when needed and what needed. \$\endgroup\$ – Xriuk Jan 14 '16 at 9:20
0
\$\begingroup\$

SDL Wiki SDL_LockTexture function:

pixels: this is filled in with a pointer to the locked pixels, appropriately offset by the locked area

So based on this I imagined that I was given a block of pixels padded by the rect's X and Y coordinates so to get to the first pixel I needed to manually get to it, like I tried to do:

Uint32* d = dest_buffer + dest_rect.y*dest_row_span + dest_rect.x;

And I was getting access violation on writing, on the only rect where the sum of X coordinate and WIDTH was lower than the pitch, so I started realizing that for some reason I was going out of bounds in that specific rect.
Then I tried to use SDL_UpdateTexture and everything worked flawlessly! So I started inspecting SDL's source code and came near the SDL_LockTexture function, particularly when the pixels parameter is set as follows:

*pixels =
        (void *) ((Uint8 *) surface->pixels + rect->y * surface->pitch +
                  rect->x * surface->format->BytesPerPixel);

So, indeed pixels points already to the beginning of the locked pixels!!!
And my function becomes this:

void XGE_AwsSurface::Paint(unsigned char* src_buffer, int src_row_span, const aws::Rect &src_rect, const aws::Rect &dest_rect){
    Uint32* src_buffer_i = (Uint32*)src_buffer;
    src_row_span /= 4;
    int dest_row_span;
    Uint32* dest_buffer;
    SDL_Rect dst_rect = XGE_AwsRectToSDL(dest_rect);
    SDL_LockTexture(texture, &dst_rect, (void**)&dest_buffer, &dest_row_span);
    dest_row_span /= 4;
    Uint32* s = src_buffer_i + src_rect.y*src_row_span + src_rect.x;
    Uint32* d = dest_buffer;
    for(int y = 0; y < dst_rect.h; y++){
        for(int x = 0; x < dst_rect.w; x++){
            *d = *s;
            d++;
            s++;
        }
        d += dest_row_span - dst_rect.w;
        s += src_row_span - src_rect.width;
    }
    SDL_UnlockTexture(texture);
}

I hope this helps someone in trouble...

\$\endgroup\$
  • \$\begingroup\$ So wait, surprise surprise, SDL does what the docs say? \$\endgroup\$ – Tyyppi_77 Jan 21 '16 at 20:46
  • \$\begingroup\$ Doesn't "appropriately offset by the locked area" mean to you that pixels have non zero origin? \$\endgroup\$ – Xriuk Jan 22 '16 at 10:02
  • \$\begingroup\$ No, it means that the pixel at (0, 0) in the array corresponds to the pixel in the texture at (rect.x, rect.y). \$\endgroup\$ – Tyyppi_77 Jan 22 '16 at 10:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.