Not logged inGosu Forums
Forum back to libgosu.org Help Search Register Login
Up Topic Gosu / Gosu Exchange / Image drawing performance
- - By antm Date 2019-03-24 15:42
I've just started playing around with Gosu and I really like it but I am having an issue with the performance of image drawing that I hope somebody might be able to help me with.

I've set up a very basic prototype that creates a non-full screen window and draws a single 1024x768 png image each cycle. 

When I run this under Windows 10, I get a frame rate of about 18 fps.  However if I run the same code on the same machine under Linux (via an Ubuntu 18.04 Live CD) I get a consistent 60 fps.

Back in Windows, if I run an equivalent C implementation using the SDL2 library directly, I get about 300 fps.

I'm running this on a Intel Core i7 620 M which has an integrated Intel HD Graphics adaptor.  It's pretty elderly so I expect it doesn't support the more recent versions of OpenGL.  Initially I thought this might be the issue but the Linux and C/SDL tests indicate that it should be capable of more.  I'm guessing that when running under Windows, Gosu is resorting to some sort of software rendering which is impacting the performance.

Windows tells me I've got the latest video drivers available and I can't find anything later that looks to be compatible on the Intel site.

Ruby version is ruby 2.5.3p105 (2018-10-18 revision 65156) [x64-mingw32]

Gosu version is 0.14.5

Is there anything I can do to improve the frame rate, or at least try to work out what is happening?

Thanks.
Parent - - By jlnr (dev) Date 2019-03-25 15:29
Do you use OpenGL in the equivalent SDL 2 code as well? I think they have this "renderer" library that uses OpenGL under the hood, but is easier than using raw OpenGL. If it works from C but not via Ruby -> Gosu -> SDL 2, then that's really curious.

This is what Gosu does: https://github.com/gosu/gosu/blob/master/src/Window.cpp#L37-L47

Usually these kinds of issues are solved by reinstalling drivers or windows or whatever, but that's obviously not a great solution. :/ OpenGL 2.1 (what your chip supposedly supports) should be good enough as well.
Parent - - By antm Date 2019-03-25 19:08
Thanks for the reply.

Directly interfacing with OpenGL is a bit beyond my knowledge level at the moment so I was making use of the SDL renderer in the C++ implementation.

For reference, this is the C++ code with the error checking etc stripped out:

#include "SDL.h"
#include "SDL_image.h"
#include <iostream>

int main(int argc, char* args[])
{
  SDL_Init(SDL_INIT_VIDEO);
  IMG_Init(IMG_INIT_PNG);

  SDL_Window* window = nullptr;
  SDL_Renderer* renderer = nullptr;
  SDL_CreateWindowAndRenderer(1024, 768, 0, &window, &renderer);
  SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);

  SDL_Surface* surface = IMG_Load("background.png");
  SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
  SDL_FreeSurface(surface);

  int dt = 0;
  int frames = 0;
  bool running = true;
  uint32_t ticks = SDL_GetTicks();
  SDL_Event event;

  while (running) {
    while (SDL_PollEvent(&event)) {
      if (event.type == SDL_QUIT) {
        running = false;
      }
    }

    ++frames;
    dt = SDL_GetTicks() - ticks;
    if (dt >= 1000) {
      std::cout << frames / (dt / 1000.0) << '\n';
      ticks += dt;
      frames = 0;
    }

    SDL_RenderClear(renderer);
    SDL_RenderCopy(renderer, texture, NULL, NULL);
    SDL_RenderPresent(renderer);
  }

  SDL_DestroyTexture(texture);
  SDL_DestroyWindow(window);
  SDL_DestroyRenderer(renderer);
  SDL_Quit();

  return 0;
}


This is what I am trying in Ruby:

require 'gosu'

class Window < Gosu::Window
  def initialize(*args)
    super
    @background = Gosu::Image.new('background.png')
    @frames = 0
    @ticks = Gosu.milliseconds
  end

  def update
    @frames += 1
    dt = Gosu.milliseconds - @ticks
    return unless dt >= 1000

    puts @frames / (dt / 1000.0)
    @ticks += dt
    @frames = 0
  end

  def draw
    @background.draw(0, 0, 0)
  end

  def button_down(id)
    case id
    when Gosu::KbEscape
      close
    end
  end 
end

window = Window.new(1024, 768)
window.show


The image is a 1024x768 PNG, nothing special that I am aware of.

My C++ is very limited but I'll have a look through the code you've linked to see if I can put together a more fair comparison.

Thanks again, it's a great library and I hope to get some good use out of it.
Parent - - By jlnr (dev) Date 2019-03-26 10:53
Thanks for trying this and posting the code. It seems that SDL_Renderer does not necessarily use OpenGL on Windows, so maybe SDL 2 works better because it uses Direct3D.

Can you please try calling SDL_CreateWindow and SDL_CreateRenderer separately as in this example:

https://wiki.libsdl.org/SDL_CreateRenderer

I guess you could try different indices for the renderer (0, 1, 2 instead of -1) and then print the name of the renderer using this function:

https://wiki.libsdl.org/SDL_GetRenderDriverInfo

If either the OpenGL or OpenGL ES driver works better than what Gosu does, then I could fix it. But adding a Direct3D backend to Gosu itself would be too much :(
Parent - - By antm Date 2019-03-26 19:37
Looks like you were right regarding SDL2 using a Direct3D driver.

While running Windows, if I use the SDL_CreateWindowAndRenderer function, SDL_GetRenderDriverInfo shows the resulting renderer as 'direct3d', with the flags SDL_RENDERER_ACCELERATED and SDL_RENDERER_TARGETTEXTURE set.

If I create the renderer separately with no flags passed, it again results in a 'direct3d' renderer with SDL_RENDERER_ACCELERATED and SDL_RENDERER_TARGETTEXTURE set.  This combination results in a FPS around the 475 mark.

If I set the SDL_RENDERER_SOFTWARE flag, I get a 'software' renderer and performance around the 265 FPS mark.

If I use SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl"), I get an 'opengl' renderer with SDL_RENDERER_ACCELERATED and SDL_RENDERER_TARGETTEXTURE set.  This results in about 275 FPS.

Repeating the exercise under Ubuntu (again using a Live CD on the same machine), the default renderer is 'opengl' and I get a frame rate around 215 FPS.

Still a bit confused as to why I get such different frame rates when running the same Ruby script under Windows (18/19 FPS) than Linux (60 FPS).  Possibly the drivers used by Ubuntu are better than what is on available on my Windows 10 build?

Thanks for taking the time to reply anyway.  Guess I might have to treat myself to some hardware with a better graphics card :-)
Parent - - By jlnr (dev) Date 2019-04-01 12:54
Hey, where did my reply go? :C

Thanks for digging into this! These OpenGL issues on Windows come up from time to time and it would be really good to know if there's anything I can do in Gosu to fix them. Your "opengl" renderer with 275 FPS and SDL_RENDERER_ACCELERATED doesn't sound like it's just software?!

Can you please try a "pure OpenGL" game like Super Tux Kart to see if it runs acceptably on your PC? Gosu is something between 15 and 20 years old, so your GPU really shouldn't be the problem. I've just recently added the first non-OpenGL 1.0 call, and it's an optional feature (render-to-texture) :)
Parent - - By antm Date 2019-04-02 19:01
I had a quick go with Super Tux Kart.  It complained that Open GL 3.1 wasn't available but did allow me to play.  If I'm interpreting the FPS information it showed correctly, it was getting around 25 FPS when run in a 1024x768 window.

Not sure it helps much but I also downloaded a utility called GpuTest and when running the plot3D benchmark/module I was getting about 3 FPS.  Happy to run some other tests if there is any thing else you want me to try.

I've tried removing and re-installing the video driver but it doesn't seem to make any difference.
Parent - By jlnr (dev) Date 2019-04-04 07:07
Thanks for testing. Hm! If Super Tux Kart can manage 25 FPS, then Gosu should run way faster than 18 FPS?! If I can find the time I'll look at their OpenGL code. Maybe there's some flag that I set that makes the Intel drivers unhappy.
Up Topic Gosu / Gosu Exchange / Image drawing performance

Powered by mwForum 2.29.7 © 1999-2015 Markus Wichitill