Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: GetDC() NULL  (Read 8983 times)

0 Members and 3 Guests are viewing this topic.

Synyster_Coder

  • Newbie
  • *
  • Posts: 20
    • View Profile
    • Email
GetDC() NULL
« on: September 17, 2014, 12:21:14 pm »
I have made a game that requires lots of render textures to be created, my game seems to break when a function in WglContext.cpp (the constructor) is called, this function is called GetDC() it returns me NULL. After doing some research on the interwebs MSDN says "If the function fails, the return value is NULL." and "The number of DCs is limited only by available memory." My system has 16 GB of ram and it's not even coming close to this.

I have created a program to simulate this issue:

#include <iostream>
#include <vector>
#include "SFML\Window.hpp"
#include "SFML\Graphics.hpp"

using namespace std;

void render();
sf::Texture* text;
sf::Sprite sprt;
vector<sf::Sprite*> windowSprites;
vector<sf::RenderTexture*> rndText;
sf::RenderWindow* window;

int main()
{
        text = new sf::Texture();
        text->loadFromFile("image.png");
        sprt.setTexture((*text));
        window = new sf::RenderWindow(sf::VideoMode(0,0,900,527),"Window");

        for(int i = 0; i < 200; i++)
        {
                rndText.push_back(new sf::RenderTexture());
                rndText[i]->create(900,527);
                windowSprites.push_back(new sf::Sprite());
                windowSprites[i]->setTexture(rndText[i]->getTexture());
                cout << i << endl;
                render();
        }
        while(true)
        {
                render();
        }
        return 0;
}

void render()
{
        window->clear();
        for(int i = 0; i < rndText.size(); i++)
        {
                rndText[i]->clear();
                rndText[i]->draw(sprt);
                rndText[i]->display();
                window->draw((*windowSprites[i]));
        }
        window->display();
}
 

It seems to be pretty random when GetDC() returns NULL, can anyone shed any light on this?!

Thanks Guys!

AlexAUT

  • Sr. Member
  • ****
  • Posts: 396
    • View Profile
Re: GetDC() NULL
« Reply #1 on: September 17, 2014, 12:44:41 pm »
First the actual content of a RenderTexture is stored on the GPU, like every texture. Only sf::Image is stored in RAM.

Quick calculation:

1 Pixel = 4bytes (R8G8B8A8) => 1RenderTexture = 900*527*4 = ~2mb + Depth/Stecilbuffer? on the GPU => 200 RenderTextures * 2mb = ~400+mb. I dont know how much memory your GPU has, but keep in mind that sf::Window creates two FBOs (Double buffering) every texture uses GPU memory and the OS aswell.

To not trust my calculation  ;)


To your code:

*Avoid manual memory managment (new/delete, actually you do not call delete = your code leaks...). Use smartpointers or in this case just store the element directly.
*sf::VideoMode(0,0,900,527) should be sf::VideoMode(900,527) I guess?
*I don't know if you did it because it is a test example but include the sfml classes instead of System/Window...hpp, saves a lot of compile time

AlexAUT
« Last Edit: September 17, 2014, 12:49:06 pm by AlexAUT »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: GetDC() NULL
« Reply #2 on: September 17, 2014, 12:50:03 pm »
Don't use globals, especially not with SFML.

Besides that there are also a few other things:

  • Use the cross-platform way of path, which is a slash instead of a backslash (e.g. SFML/Window.hpp).
  • Add SFML to the project file as described in the official tutorials and then use <> around SFML includes (e.g. #include <SFML/Window.hpp>).
  • Don't use using namespace std; it will pull all the symbols from the std namespace into the global namespace. You'll create possible name conflicts and it will be harder to figure out if a class is self written or from the standard C++ library.
  • Use classes to structure your program, so you don't have to use global variables and functions.
  • Use RAII and stop using manual memory management (new/delete).
  • By using RAII you should use std::unique_ptr as replacement for most raw pointers.

As AlexAUT pointed out, it might be a memory issue on your GPU. Do you really need that many render textures?
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Synyster_Coder

  • Newbie
  • *
  • Posts: 20
    • View Profile
    • Email
Re: GetDC() NULL
« Reply #3 on: September 17, 2014, 12:59:47 pm »
Yeah it's not the best coding example I don't usually use new without deleting them later, or global points, I'm not a dumbass however this still points out the problem. The GPU has 2GB of memory, take out the 315MB that windows uses leaves over 1750~mb of free GPU memory. Opening up a graphics monitor shows that the card only uses around 635mb.

AlexAUT your calculation is correct.

Yes I do need that many render textures.

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: GetDC() NULL
« Reply #4 on: September 17, 2014, 07:38:49 pm »
I do need that many render textures.
Why?

Seriously, I'm genuinely interested to know of a situation where 200 render textures the full size of the window would be required.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: GetDC() NULL
« Reply #5 on: September 17, 2014, 09:18:29 pm »
Back to C++ gamedev with SFML in May 2023

Jesper Juhl

  • Hero Member
  • *****
  • Posts: 1405
    • View Profile
    • Email
Re: GetDC() NULL
« Reply #6 on: September 18, 2014, 12:48:31 am »
And let's now get a serious answer - please.

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: GetDC() NULL
« Reply #7 on: September 18, 2014, 01:34:14 am »
The error probably isn't so much caused by GetDC() failing as opposed to CreateWindow() failing. Many SFML beginners do not understand that sf::RenderTexture is a bit more than "just a simple FBO". It owns its own context, and because of that it also has to own its own OS window in the current implementation. The number of device contexts that are associated with a window may be a large number (although I always take "limited by available memory" statements with a pinch of salt), but the number of windows a process creates might not. If GetDC() is fed a bogus window handle to begin with, it will return NULL as well.

Like the guys before me have already asked: Why do you need so many sf::RenderTextures? I can't think of a situation where I would need nearly that many myself. Not even if I went ahead and implemented some kind of indirect renderer purely with SFML. This is sounding more and more like another manifestation of the XY problem that pops up every now and then. Explaining to us the problem you are trying to solve instead of asking us how to make your tentative solution work would probably be more productive, considering that the problem you are having with sf::RenderTexture is tied to system resource limits.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Synyster_Coder

  • Newbie
  • *
  • Posts: 20
    • View Profile
    • Email
Re: GetDC() NULL
« Reply #8 on: September 18, 2014, 10:26:48 am »
Interesting, well if render textures are not the most appropriate thing to use then what should be used instead? I require something that I can draw to, then draw that to a window with a lot of other sprites.

The act of creating 200 was only to guarantee the problem happening every time, I actually only use around 18-36 depending on the game, and the problem is intermittent some times it does break some times it doesn't.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
AW: GetDC() NULL
« Reply #9 on: September 18, 2014, 10:28:40 am »
You can reuse a render texture.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Synyster_Coder

  • Newbie
  • *
  • Posts: 20
    • View Profile
    • Email
Re: GetDC() NULL
« Reply #10 on: September 18, 2014, 10:36:35 am »
As much as this may be a good solution it's not really very suitable for my needs, it would require quite a lot of change, is there nothing else that can be drawn to?

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
AW: GetDC() NULL
« Reply #11 on: September 18, 2014, 10:41:35 am »
No.

Btw. we still don't know why you need that many (or less). What exactly do you do in you application?
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Synyster_Coder

  • Newbie
  • *
  • Posts: 20
    • View Profile
    • Email
Re: GetDC() NULL
« Reply #12 on: September 18, 2014, 10:52:35 am »
OK thanks, that's all I needed to know. If there isn't already maybe a small message in the render texture documentation should mention that a limited amount can be created depending on system resources.

The system is not something i have written on my own it's a team of people that have been working on it for about 3-4 years and this functionality has been in it from the start it's only becoming a problem now due to the complexity of the games we are making. This is a system that cannot be changed at such a fundamental part so we will need to think up a good solution for this.

Thanks for your help everyone.

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: GetDC() NULL
« Reply #13 on: September 18, 2014, 02:29:40 pm »
If there isn't already maybe a small message in the render texture documentation should mention that a limited amount can be created depending on system resources.
SFML can be run on OpenGL 1.2 hardware. This dates back to the 1990s when video RAM capacity didn't surpass 16MB or maybe 32MB on high end cards. Do you think we should add a note to sf::Texture that mentions that a limited amount can be created depending on system resources as well? I think every established developer should have a feeling or intuition for what kind of resources they are creating and their underlying requirements. If you have an idea of how SFML implements its classes, you can also roughly estimate when you will hit the limit. I admit that you probably didn't know how sf::RenderTexture is implemented because it isn't documented, but since you did do a step-through debug and realized the stuff with GetDC() you might have also seen the window creation as well.

Ultimately, everything you can create is limited by system resources in one way or another. What we would and should do is warn users of abnormally low limits that don't fit intuition and sf::RenderTexture doesn't fall into that category if you ask me. "Typical usage" of sf::RenderTexture doesn't require creating that many of them.

The system is not something i have written on my own it's a team of people that have been working on it for about 3-4 years and this functionality has been in it from the start it's only becoming a problem now due to the complexity of the games we are making. This is a system that cannot be changed at such a fundamental part so we will need to think up a good solution for this.
I don't mean to be offensive, but did you guys ever think about the scalability of the system? Something that might work on a small scale might not work on a larger scale, such as the current implementation using so many sf::RenderTextures.

You hear the argument a lot that "xyz cannot be changed because it has been around for a while" and I have to counter argue that if xyz has been around for a while, surely the requirements of the project that it was originally written for cannot be the same as the projects to which it is applied now. I know refactoring is hard, and in the short term it doesn't yield much if any results, but if done right you can future-proof your framework for the next few years.

Interesting, well if render textures are not the most appropriate thing to use then what should be used instead? I require something that I can draw to, then draw that to a window with a lot of other sprites.
This also has me wondering: If you draw to a sf::RenderTexture just to draw the generated image to the framebuffer anyway, why even bother with the extra step? Surely there must be something else you are doing that doesn't make drawing directly to the backbuffer as simple as it sounds. If there is nothing else, then I regret to have to tell you that what you are doing is very very inefficient.

If you can provide a more complete picture of what exactly is being drawn and how it is drawn (with shaders, custom blending, etc.) we can provide more suggestions for improvements.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).