如果图片大小>1 * 1,则在第二个OpenGL线程中显示黑色纹理

ccgok5k5  于 2022-11-23  发布在  其他
关注(0)|答案(1)|浏览(109)

我不得不在我的项目中使用多线程,我的问题是,在第二个线程中,我注册了一个纹理,如果这个纹理的宽度和高度大于1像素,纹理将被渲染为黑色否则效果很好...
我使用两个OpenGL上下文和三个线程。
下面是一个独立的代码,它可以很好地与两个图片:blue.jpg和red.jpg(如果red.jpg的宽度和高度均为1个像素)。

#include <SDL.h>
#include <SDL_image.h>
#include <gl.h>
#include <glu.h>
#include <cstring>
#include <thread>
#include <iostream>
#include <windows.h>
#include <wingdi.h>
#define WINDOW_WIDTH 1365
#define WINDOW_HEIGHT 704
using namespace std;

SDL_Window *screen;
SDL_GLContext ctx, ctxa;

SDL_Surface *flipSurface(SDL_Surface *surface)
{
    int current_line, pitch;
    SDL_Surface *fliped_surface = SDL_CreateRGBSurface(SDL_SWSURFACE, surface->w,surface->h, surface->format->BitsPerPixel, surface->format->Rmask, surface->format->Gmask, surface->format->Bmask, surface->format->Amask);
    SDL_LockSurface(surface);
    SDL_LockSurface(fliped_surface);
    pitch = surface->pitch;
    for(current_line = 0; current_line < surface->h; current_line++)
        memcpy(&((unsigned char*)fliped_surface->pixels)[current_line*pitch], &((unsigned char*)surface->pixels)[(surface->h - 1  - current_line)*pitch], pitch);
    SDL_UnlockSurface(fliped_surface);
    SDL_UnlockSurface(surface);
    return fliped_surface;
}

GLuint loadTexture(const char *filename, bool useMipMap)
{
    GLuint glID;
    SDL_Surface * picture_surface = NULL;
    SDL_Surface *gl_surface = NULL;
    SDL_Surface * gl_fliped_surface = NULL;
    Uint32 rmask, gmask, bmask, amask;
    picture_surface = IMG_Load(filename);
    if (picture_surface == NULL)
        return 0;
    #if SDL_BYTEORDER == SDL_BIG_ENDIAN
        rmask = 0xff000000;
        gmask = 0x00ff0000;
        bmask = 0x0000ff00;
        amask = 0x000000ff;
    #else

        rmask = 0x000000ff;
        gmask = 0x0000ff00;
        bmask = 0x00ff0000;
        amask = 0xff000000;
    #endif
    SDL_PixelFormat format = *(picture_surface->format);
    format.BitsPerPixel = 32;
    format.BytesPerPixel = 4;
    format.Rmask = rmask;
    format.Gmask = gmask;
    format.Bmask = bmask;
    format.Amask = amask;
    gl_surface = SDL_ConvertSurface(picture_surface,&format,SDL_SWSURFACE);
    gl_fliped_surface = flipSurface(gl_surface);
    glGenTextures(1, &glID);
    glBindTexture(GL_TEXTURE_2D, glID);
    if(useMipMap)
    {
        gluBuild2DMipmaps(GL_TEXTURE_2D, 4, gl_fliped_surface->w, gl_fliped_surface->h, GL_RGBA,GL_UNSIGNED_BYTE, gl_fliped_surface->pixels);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    }
    else
    {
        glTexImage2D(GL_TEXTURE_2D, 0, 4, gl_fliped_surface->w, gl_fliped_surface->h, 0, GL_RGBA,GL_UNSIGNED_BYTE, gl_fliped_surface->pixels);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    }
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    SDL_FreeSurface(gl_fliped_surface);
    SDL_FreeSurface(gl_surface);
    SDL_FreeSurface(picture_surface);
    return glID;
}

GLuint texture = 0;

void render(GLuint picture)
{
    glBindTexture(GL_TEXTURE_2D, picture);
    glBegin(GL_QUADS);
        glTexCoord2i(0, 0);glVertex3d(-1,-1,picture);
        glTexCoord2i(0, 1);glVertex3d(-1,1,picture);
        glTexCoord2i(1, 1);glVertex3d(1,1,picture);
        glTexCoord2i(1, 0);glVertex3d(1,-1,picture);
    glEnd();
    cout << picture << "^" << endl;
}

bool needRegister = false;

void textureManager()
{
    SDL_GL_MakeCurrent(screen, ctxa);
    while(1)
    {
        if(needRegister)
        {
            texture = loadTexture("red.jpg", false);
            needRegister = false;
            cout << texture << endl;
        }
        SDL_Delay(50);
    }
}

GLuint registerRed()
{
    needRegister = true;
    while(1)
    {
        SDL_Delay(50);
        if(texture)
            return texture;
    }
}

void b()
{
    SDL_Init(SDL_INIT_VIDEO);
    screen = SDL_CreateWindow("My App", 100, 100, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL);
    SDL_Event event;

    ctx = SDL_GL_CreateContext(screen);
    ctxa = SDL_GL_CreateContext(screen);
    bool a = wglShareLists((HGLRC)ctx, (HGLRC)ctxa);
    SDL_GL_MakeCurrent(screen, ctx);
    thread registerRedThread = thread(&textureManager);

    bool running = true;

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(70, (double)WINDOW_WIDTH / WINDOW_HEIGHT, 1, 100);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_TEXTURE_2D);

    GLuint blue = loadTexture("blue.jpg", false);
    registerRed();
    cout << endl << "Registered: " << texture << endl << endl;

    while(running)
    {
        SDL_PollEvent(&event);
        switch(event.type)
        {
            case SDL_QUIT:
                {
                    running = false;
                    break;
                }
        }

        cout << SDL_GetTicks() << endl;
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        gluLookAt(3, 4, 0, 0, 0, 1, 0, 0, 1);

        render(blue);
        if(texture != 0)
        {
            cout << "@" << blue << " " << texture << endl;
            cout << "Rendering the red picture..." << endl;
            render(texture);
        }

        glFlush();
        SDL_GL_SwapWindow(screen);

        SDL_Delay(1000);
    }
    registerRedThread.detach();
    SDL_Quit();
}

thread a;

int main(int argc, char** argv)
{
    a = thread(&b);
    while(1);
    return 0;
}

此外,如果我们在第一张图片(在“第一”线程中注册)中尝试相同的测试,效果很好......我们可以使用多像素纹理、其他颜色和透明度。我不明白为什么问题只发生在第二个线程中
编辑:此外,如果我使用一个透明的图片注册在其他线程,我只是看到一个空白的图片。

7nbnzgx9

7nbnzgx91#

正如@PeterT在评论中所说:
驱动程序优化可能已经得到了你。在我的NVIDIA卡上,如果我在texture = loadTexture("red.jpg", false);之后添加一个glFlush(),它就能工作
我想glFinish()会是更正确的方法。无论如何,只要确保所有关于纹理上传的命令都已经执行。

相关问题