You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用SDL2渲染曼德博集合时出现重影及内存上涨问题求助

曼德博集合SDL2渲染问题:旧图像无法清除+内存占用上涨

我用C++写了曼德博集合渲染代码,通过SDL2库显示图像。设置按下W键时清除旧图像并以新参数渲染,但旧图像始终无法清除,且每次按W键内存占用都会上升,该怎么解决?

原代码

#include <complex>
#include <iostream>
#include <SDL.h>
#include <chrono>
#include <omp.h>
using namespace std;

int main(int argc, char** argv) {
    const int resolution= 2000;

    const int rows = resolution;
    const int cols = resolution;
    complex<long double> position;
    
    int dots[rows][cols];
    for (int i = 0; i < rows; ++i) {
        for (int j = 0; j < cols; ++j) {
            dots[i][j] = 0;
        }
    }
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        std::cerr << "SDL initialization failed: " << SDL_GetError() << std::endl;
        return 1;
    }

    const int screenWidth = cols * 1; // Adjust the window size as needed
    const int screenHeight = rows * 1;
    SDL_Window* window = SDL_CreateWindow("Mandelbrot set Visualization", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, screenWidth, screenHeight, SDL_WINDOW_SHOWN);
    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    SDL_Rect rect;

    long double startx = -2;
    long double endx = 2;
    long double starty = 2;
    long double endy = -2;
    
    long double stepx = (endx - startx) / (cols - 1);
    long double stepy = (endy - starty) / (rows - 1);

    rect.w = screenWidth / cols;
    rect.h = screenHeight / rows;

    int numThreads = 16;
    omp_set_num_threads(numThreads);

    #pragma omp parallel
    {
        int threadID = omp_get_thread_num(); // Get the thread ID

    #pragma omp for
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                long double real = startx + j * stepx;
                long double imag = starty + i * stepy;
                position = complex<long double>(real, imag);
                complex<long double> iterate(0, 0);
                int color = 0;
                for (int n = 0; n < 256; n++) {
                    iterate = iterate * iterate + position;
                    color++;
                    if (abs(iterate) > 2) {
                        dots[i][j] = color;
                        break;
                    }
                }
            }
        }
    }
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {

            SDL_SetRenderDrawColor(renderer, 0, dots[i][j], dots[i][j], 255); 


            rect.x = j * (screenWidth / cols);
            rect.y = i * (screenHeight / rows);
            SDL_RenderFillRect(renderer, &rect);
        }
    }
    SDL_RenderPresent(renderer);



    // Main game loop
    bool quit = false;
    SDL_Event event;
    while (!quit) {
        while (SDL_PollEvent(&event)) {
            if (event.type == SDL_QUIT) {
                quit = true;
            }
            else if (event.type == SDL_KEYDOWN) {
                if (event.key.keysym.sym == SDLK_w) {
                    // Zoom or change parameters, as needed
                    cout << "loop start";
                    SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
                    SDL_RenderClear(renderer);
                    long double decreaseAmountx = (abs(endx) + abs(startx)) / 20;
                    long double decreaseAmounty = (abs(endy) + abs(starty)) / 20;
                    endx -= decreaseAmountx;
                    startx += decreaseAmountx;
                    endy += decreaseAmounty;
                    starty -= decreaseAmounty;
                    stepx = (endx - startx) / (cols - 1);
                    stepy = (endy - starty) / (rows - 1);
                    // Render the Mandelbrot set with new parameters
                    #pragma omp parallel
                    {
                        int threadID = omp_get_thread_num(); // Get the thread ID

                        #pragma omp for
                        for (int i = 0; i < rows; i++) {
                            for (int j = 0; j < cols; j++) {
                                long double real = startx + j * stepx;
                                long double imag = starty + i * stepy;
                                position = complex<long double>(real, imag);
                                complex<long double> iterate(0, 0);
                                int color = 0;
                                for (int n = 0; n < 256; n++) {
                                    iterate = iterate * iterate + position;
                                    color++;
                                    if (abs(iterate) > 2) {
                                        dots[i][j] = color;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    for (int i = 0; i < rows; i++) {
                        for (int j = 0; j < cols; j++) {

                            SDL_SetRenderDrawColor(renderer, 0, dots[i][j], dots[i][j], 255); 


                            rect.x = j * (screenWidth / cols);
                            rect.y = i * (screenHeight / rows);
                            SDL_RenderFillRect(renderer, &rect);
                        }
                    }
                    cout << "Present";
                    SDL_RenderPresent(renderer);
                    

                }
                else if (event.key.keysym.sym == SDLK_r) {
                    // Trigger an SDL_QUIT event to exit the application
                    SDL_Event quitEvent;
                    quitEvent.type = SDL_QUIT;
                    SDL_PushEvent(&quitEvent);
                }
            }
        }
    }

    // Cleanup and quit
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}

问题原因及修复方案

1. 旧图像无法清除的核心原因

  • 未更新集合内点的颜色值:原代码中,只有当点跳出曼德博集合(abs(iterate)>2)时才会给dots[i][j]赋值,而集合内的点会保留上一次计算的旧值,导致绘制时旧图像残留。
  • 渲染器同步问题:加速渲染器的SDL_RenderClear操作可能未及时生效,导致清除操作被延后。

修复:

  • 无论点是否在集合内,计算完成后都给dots[i][j]赋值:
    // 替换原计算循环内的赋值逻辑
    for (int n = 0; n < 256; n++) {
        iterate = iterate * iterate + position;
        color++;
        if (abs(iterate) > 2) {
            break;
        }
    }
    dots[i][j] = color; // 确保所有点都被更新
    
  • 清除后强制刷新渲染器,确保清除操作完成:
    SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
    if (SDL_RenderClear(renderer) != 0) {
        cerr << "SDL_RenderClear错误: " << SDL_GetError() << endl;
    }
    SDL_RenderFlush(renderer); // 强制完成清除操作
    

2. 内存占用上升的原因

  • 栈溢出:int dots[rows][cols]是在栈上分配的2000×2000的int数组(约16MB),远超默认栈大小(通常8MB),导致系统自动补充堆内存,引发内存占用异常上升。
  • 线程竞争隐患:全局的position变量被多线程共享,可能导致未定义行为和内存异常。

修复:

  • 将dots改为堆分配,使用vector自动管理内存:
    // 替换原int dots[rows][cols];及初始化代码
    vector<vector<int>> dots(rows, vector<int>(cols, 0));
    
  • 将position移到循环内部,避免多线程共享:
    // 在并行循环内创建position,每个线程独立使用
    complex<long double> position(real, imag);
    

优化后的关键代码片段

初始化部分

const int resolution= 2000;
const int rows = resolution;
const int cols = resolution;

// 改用vector分配堆内存,避免栈溢出
vector<vector<int>> dots(rows, vector<int>(cols, 0));

W键处理逻辑

if (event.key.keysym.sym == SDLK_w) {
    cout << "loop start";
    // 清除旧图像
    SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
    if (SDL_RenderClear(renderer) != 0) {
        cerr << "SDL_RenderClear错误: " << SDL_GetError() << endl;
    }
    SDL_RenderFlush(renderer);

    // 更新参数
    long double decreaseAmountx = (abs(endx) + abs(startx)) / 20;
    long double decreaseAmounty = (abs(endy) + abs(starty)) / 20;
    endx -= decreaseAmountx;
    startx += decreaseAmountx;
    endy += decreaseAmounty;
    starty -= decreaseAmounty;
    stepx = (endx - startx) / (cols - 1);
    stepy = (endy - starty) / (rows - 1);

    // 并行计算曼德博集合
    #pragma omp parallel
    {
        #pragma omp for
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                long double real = startx + j * stepx;
                long double imag = starty + i * stepy;
                // 每个线程独立创建position,避免竞争
                complex<long double> position(real, imag);
                complex<long double> iterate(0, 0);
                int color = 0;
                for (int n = 0; n < 256; n++) {
                    iterate = iterate * iterate + position;
                    color++;
                    if (abs(iterate) > 2) {
                        break;
                    }
                }
                // 确保所有点都更新颜色值
                dots[i][j] = color;
            }
        }
    }

    // 绘制新图像
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            SDL_SetRenderDrawColor(renderer, 0, dots[i][j], dots[i][j], 255); 
            rect.x = j * (screenWidth / cols);
            rect.y = i * (screenHeight / rows);
            SDL_RenderFillRect(renderer, &rect);
        }
    }
    cout << "Present";
    SDL_RenderPresent(renderer);
}

内容的提问来源于stack exchange,提问作者Parsa Eslami

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 23:09:51