簡體   English   中英

調整大小后 wxGLCanvas 巨大的內存使用量

[英]wxGLCanvas huge memory usage after resizing

我創建了一個簡單的 wxGLCanvas 來使用 wxWidgets 演示 OpenGl。 該演示工作正常,除了在調整窗口大小時,內存使用量從幾兆字節增加到近 400 兆字節,並且它保持在那里並且不會減少,這里是代碼片段。

// ctor
TriangleCanvas::TriangleCanvas(wxWindow* parent, wxGLAttributes& attribList)
    : wxGLCanvas(parent, attribList, wxID_ANY, { 0,0 }, wxDefaultSize),
    m_vbo(0), m_vao(0), ctx_attr(new wxGLContextAttrs)
{
    
    ctx_attr->CoreProfile().OGLVersion(4, 3).EndList();
    m_context = new wxGLContext(this, NULL, ctx_attr);
    Bind(wxEVT_PAINT, &TriangleCanvas::OnPaint, this);
    Bind(wxEVT_SIZE, &TriangleCanvas::Resize, this);
}


// Paint method
void TriangleCanvas::OnPaint(wxPaintEvent& event)
{
    wxPaintDC(this);
    SetCurrent(*m_context);
    shader->use();

    // set background to black
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // draw the graphics
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ebo);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    
    glFlush();
    SwapBuffers();
}

void TriangleCanvas::Resize(wxSizeEvent& event) {
    event.Skip();
    glViewport(0, 0, event.GetSize().x, event.GetSize().y);

    if (!setup) {
        InitializeGLEW();
        SetupGraphics();
    }   
}

提前致謝。

我認為將 wxGLCanvas 與擴展加載器一起使用的最佳方法是使用輔助類並將所有 OpenGL 繪圖保留在該輔助類的 cpp 部分中。

例如,這是一個繪制三角形的小助手類:

幫助文件

#ifndef GLHELPER_H_INCLUDED
#define GLHELPER_H_INCLUDED

class GLHelper
{
public:
    bool InitGlew();
    void Render();
    void SetSize(int w, int h);

    bool InitData();
    void Cleanup();



private:
    unsigned int m_VBO, m_VAO, m_shaderProgram;
};


#endif // GLHELPER_H_INCLUDED

ghelper.cpp

#include <GL/glew.h>

#ifdef __WXMSW__
    #include <GL/wglew.h>
#elif defined(__WXGTK__)
    #include <GL/glxew.h>
#endif // defined

#include "glhelper.h"

static const char *vertexShaderSource = "#version 330 core\n"
    "layout (location = 0) in vec3 aPos;\n"
    "void main()\n"
    "{\n"
    "   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
    "}\0";
static const char *fragmentShaderSource = "#version 330 core\n"
    "out vec4 FragColor;\n"
    "void main()\n"
    "{\n"
    "   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
    "}\n\0";

bool GLHelper::InitGlew()
{
    GLenum initStatus = glewInit();

    return initStatus == GLEW_OK;
}

bool GLHelper::InitData()
{
    unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);
    // check for shader compile errors
    int success;
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        return false;
    }
    // fragment shader
    unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);
    // check for shader compile errors
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        return false;
    }
    // link shaders
    m_shaderProgram = glCreateProgram();
    glAttachShader(m_shaderProgram, vertexShader);
    glAttachShader(m_shaderProgram, fragmentShader);
    glLinkProgram(m_shaderProgram);
    // check for linking errors
    glGetProgramiv(m_shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        return false;
    }
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    // set up vertex data (and buffer(s)) and configure vertex attributes
    // ------------------------------------------------------------------
    float vertices[] = {
        -0.5f, -0.5f, 0.0f, // left
         0.5f, -0.5f, 0.0f, // right
         0.0f,  0.5f, 0.0f  // top
    };

    //unsigned int VBO, VAO;
    glGenVertexArrays(1, &m_VAO);
    glGenBuffers(1, &m_VBO);
    // bind the Vertex Array Object first, then bind and set vertex buffer(s),
    // and then configure vertex attributes(s).
    glBindVertexArray(m_VAO);

    glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    // note that this is allowed, the call to glVertexAttribPointer registered
    //VBO as the vertex attribute's bound vertex buffer object so afterwards we
    //can safely unbind
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // You can unbind the VAO afterwards so other VAO calls won't accidentally
    //modify this VAO, but this rarely happens. Modifying other VAOs requires a
    //call to glBindVertexArray anyways so we generally don't unbind VAOs (nor
    // VBOs) when it's not directly necessary.
    glBindVertexArray(0);

    return true;
}

void GLHelper::Cleanup()
{
    glDeleteVertexArrays(1, &m_VAO);
    glDeleteBuffers(1, &m_VBO);
    glDeleteProgram(m_shaderProgram);
}

void GLHelper::Render()
{
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    // draw our first triangle
    glUseProgram(m_shaderProgram);
    glBindVertexArray(m_VAO);
    // seeing as we only have a single VAO there's no need to bind it every
    //time, but we'll do so to keep things a bit more organized
    glDrawArrays(GL_TRIANGLES, 0, 3);
}

void GLHelper::SetSize(int width, int height)
{
    glViewport(0, 0, width, height);
}

這是一個簡短的演示,它使用這個輔助類來繪制三角形。

演示文件

#include "wx/wx.h"

#include <wx/glcanvas.h>
#include "glhelper.h"

class wxGlewFrame: public wxFrame
{
    public:
        wxGlewFrame(wxWindow*);
        ~wxGlewFrame();
    private:
        void OnCanvasSize(wxSizeEvent&);
        void OnCanvasPaint(wxPaintEvent&);

        void InitGL();

        wxGLCanvas* m_canvas;
        wxGLContext* m_context;
        GLHelper m_helper;
};

wxGlewFrame::wxGlewFrame(wxWindow* parent)
    : wxFrame(parent,  wxID_ANY, wxString())
{
    // Create the canvas and context.
    #if wxCHECK_VERSION(3,1,0)
        // These settings should work with any GPU from the last 10 years.
        wxGLAttributes dispAttrs;
        dispAttrs.PlatformDefaults().RGBA().DoubleBuffer().EndList();

        wxGLContextAttrs cxtAttrs;
        cxtAttrs.PlatformDefaults().CoreProfile().OGLVersion(3, 3).EndList();

        m_canvas = new wxGLCanvas(this, dispAttrs);
        m_context = new wxGLContext(m_canvas, NULL, &cxtAttrs);

        if ( !m_context->IsOK() )
        {
            SetTitle("Failed to create context.");
            return;
        }
    #else
        int dispAttrs[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_CORE_PROFILE,
                            WX_GL_MAJOR_VERSION ,3, WX_GL_MINOR_VERSION, 3, 0 };

        m_canvas = new wxGLCanvas(this, wxID_ANY, dispAttrs);
        m_context = new wxGLContext(m_canvas, NULL);

        // Unfortunately, there doesn't seem to be any way to check if the
        // context is ok prior to wxWidgets 3.1.0.
    #endif // wxCHECK_VERSION

    // On Linux, we must delay delay initialization until the canvas has
    // been full created.  On windows, we can finish now.
    #ifdef __WXMSW__
        InitGL();
    #elif defined(__WXGTK__)
        m_canvas->Bind(wxEVT_CREATE, [this](wxWindowCreateEvent&){InitGL();});
    #endif // defined
}

wxGlewFrame::~wxGlewFrame()
{
    m_helper.Cleanup();
    delete m_context;
}

void wxGlewFrame::OnCanvasSize(wxSizeEvent& event)
{
    wxSize sz = event.GetSize();
    m_helper.SetSize(sz.GetWidth(), sz.GetHeight());
    event.Skip();
}

void wxGlewFrame::OnCanvasPaint(wxPaintEvent&)
{
    wxPaintDC dc(m_canvas);

    m_helper.Render();
    m_canvas->SwapBuffers();
}

void wxGlewFrame::InitGL()
{
    // First call SetCurrent or GL initialization will fail.
    m_context->SetCurrent(*m_canvas);

    // Initialize GLEW.
    bool glewInialized = m_helper.InitGlew();

    if ( !glewInialized )
    {
        SetTitle("Failed it initialize GLEW.");
        return;
    }

    SetTitle("Context and GLEW initialized.");

    // Initialize the triangle data.
    m_helper.InitData();

    // Bind event handlers for the canvas. Binding was delayed until OpenGL was
    // initialized because these handlers will need to call OpenGL functions.
    m_canvas->Bind(wxEVT_SIZE, &wxGlewFrame::OnCanvasSize, this);
    m_canvas->Bind(wxEVT_PAINT, &wxGlewFrame::OnCanvasPaint, this);
}

class MyApp : public wxApp
{
    public:
        virtual bool OnInit()
        {
            wxGlewFrame* frame = new wxGlewFrame(NULL);
            frame->Show();
            return true;
        }
};

wxIMPLEMENT_APP(MyApp);

(這基本上是來自learnopengl.comHello Triangle示例,除了重寫為使用 wxGLCanvas 和 GLEW 而不是 GLFW 和 GLAD。

這在我的系統上占用了大約 19MB 的內存,並且在調整大小時只會增加到大約 24 或 25MB。 對於這樣一個簡單的程序來說,這聽起來可能很多,但運行官方“Hello Triangle”示例使用了 26MB。 所以我認為內存使用量應該是預期的。

順便說一句,我剛剛在論壇上發布了一個非常相似的答案。 對不起,如果那是你,我重復了我剛剛在那里發布的很多內容。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM