笔者测试环境VS2019。

基本介绍

原书作者引入Julia Sets意在使用GPU加速图形的绘制。Julia Set 是指满足下式迭代收敛的复数集合

\[Z_{n+1}=Z_{n}^2+C
\]

环境配置

跑这个例子的主要困难应该在于配置环境。这个程序依赖于openGL中的glut库。由于VS2019的整个软件架构发生了很大变化,一些链接库和头文件的位置都发生了改变,因此一些文章中的配置方法失效了。

首先我们需要获取glut库的头文件以及动态链接库。

点击这里cg-toolkit获取。安装成功之后,找到C:\Program Files (x86)\NVIDIA Corporation\Cg。注意勾选安装选项的x64相关应用。

将其中的lib文件夹中的_glut32.lib_复制到C:\Program Files (x86)\Windows Kits\10\Lib\10.0.18362.0\ucrt\x86

将其中的lib.x64文件夹中的glut32.lib复制到C:\Program Files (x86)\Windows Kits\10\Lib\10.0.18362.0\ucrt\x64并且重命名其为glut64.lib

笔者运行的是64位系统,就将bin.x64中的_glut32.dll_复制到C:\Windows\System32下

在这里下载头文件。下载完成之后,将头文件拷贝到C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\ucrt。并建立文件夹GL把它们包括起来。

提示,核心是找到C:\Program Files (x86)\Windows Kits\10,不要在Microsoft Visual Studio文件夹里浪费时间。

后面的10.0.18362.0根据版本不同可能不一致,具体问题具体分析

这个代码还需要一些别的头文件。如gl_helper.h, book.h, cpu_bitmap.h 等 在这里下载后复制到C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.2\include

主要代码

CPU Julia Set

RGBA模式中,每一个像素会保存以下数据:R值(红色分量)、G值(绿色分量)、B值(蓝色分量)和A值(alpha分量)。其中红、绿、蓝三种颜色相组合,就可以得到我们所需要的各种颜色,而alpha不直接影响颜色,它的含义是透明度。1

下面是纯粹CPU中的代码,基本的注释在代码中

  1. #include "cuda_runtime.h"
  2. #include "device_launch_parameters.h"
  3. #include "device_functions.h"
  4. #include "device_atomic_functions.h"
  5. #include <cuda.h>
  6. #include "book.h"
  7. #include <cpu_bitmap.h>
  8. #include <stdio.h>
  9. #define DIM 1000 //图像的像素边长大小
  10. struct cuComplex
  11. {
  12. float r;
  13. float i;
  14. cuComplex(float a, float b) : r(a), i(b) {}
  15. float magnitude2() { return r * r + i * i; } //计算复数的模值
  16. cuComplex operator* (const cuComplex& a)
  17. {
  18. return cuComplex(r * a.r - i * a.i, i * a.r + r * a.i);
  19. }
  20. cuComplex operator+ (const cuComplex& a)
  21. {
  22. return cuComplex(r + a.r, i + a.i);
  23. }
  24. };
  25. int julia(int x, int y)
  26. {
  27. const float scale = 1.5; //放大倍率
  28. float jx = scale * (float)(DIM / 2 - x) / (DIM / 2); //坐标变换,投影到-1~1scale
  29. float jy = scale * (float)(DIM / 2 - y) / (DIM / 2);
  30. cuComplex c(-0.8, 0.156); //基数
  31. cuComplex a(jx, jy);
  32. int i = 0;
  33. for (i = 0; i < 200; i++) //迭代
  34. {
  35. a = a * a + c;
  36. if (a.magnitude2() > 1000)
  37. return 0;
  38. }
  39. return 1;
  40. }
  41. void kernel(unsigned char* ptr)
  42. {
  43. for (int y = 0; y < DIM; y++) //遍历整个bitmap
  44. {
  45. for (int x = 0; x < DIM; x++)
  46. {
  47. int offset = x + y * DIM;
  48. int juliaValue = julia(x, y);
  49. //注意openGL这里的颜色格式是RGBA,000为黑色
  50. ptr[offset * 4 + 0] = 255 * juliaValue;
  51. ptr[offset * 4 + 1] = 0;
  52. ptr[offset * 4 + 2] = 0;
  53. ptr[offset * 4 + 3] = 255;
  54. }
  55. }
  56. }
  57. int main()
  58. {
  59. CPUBitmap bitmap(DIM, DIM);
  60. unsigned char* ptr = bitmap.get_ptr();
  61. kernel(ptr); //运行渲染
  62. bitmap.display_and_exit();
  63. }

GPU Julia Set

注意由于内核函数是global的,要在GPU上运行需要将其调用的julia函数加上device。又因为,device函数只能由device函数或者global函数调用,所以最好把结构体中的所有函数都加上device。

  1. #include "cuda_runtime.h"
  2. #include "device_launch_parameters.h"
  3. #include "device_functions.h"
  4. #include "device_atomic_functions.h"
  5. #include <cuda.h>
  6. #include "book.h"
  7. #include <cpu_bitmap.h>
  8. #include <stdio.h>
  9. //小于65536
  10. #define DIM 1000 //图像的像素边长大小
  11. struct cuComplex
  12. {
  13. float r;
  14. float i;
  15. __device__ cuComplex(float a, float b) : r(a), i(b) {}
  16. __device__ float magnitude2() { return r * r + i * i; } //计算复数的模值
  17. __device__ cuComplex operator* (const cuComplex& a)
  18. {
  19. return cuComplex(r * a.r - i * a.i, i * a.r + r * a.i);
  20. }
  21. __device__ cuComplex operator+ (const cuComplex& a)
  22. {
  23. return cuComplex(r + a.r, i + a.i);
  24. }
  25. };
  26. __device__ int julia(int x, int y)
  27. {
  28. const float scale = 1.5; //放大倍率
  29. float jx = scale * (float)(DIM / 2 - x) / (DIM / 2); //坐标变换,投影到-1~1scale
  30. float jy = scale * (float)(DIM / 2 - y) / (DIM / 2);
  31. cuComplex c(-0.8, 0.156); //基数
  32. cuComplex a(jx, jy);
  33. int i = 0;
  34. for (i = 0; i < 200; i++) //迭代
  35. {
  36. a = a * a + c;
  37. if (a.magnitude2() > 1000)
  38. return 0;
  39. }
  40. return 1;
  41. }
  42. __global__ void kernel(unsigned char* ptr)
  43. {
  44. int x = blockIdx.x; //纵向线程索引(x方向朝右,是行)
  45. int y = blockIdx.y; //纵向线程索引(y方向朝下,是列)
  46. int offset = x + y * gridDim.x;
  47. int juliaValue = julia(x, y);
  48. ptr[offset * 4 + 0] = 255 * juliaValue;
  49. ptr[offset * 4 + 1] = 0;
  50. ptr[offset * 4 + 2] = 0;
  51. ptr[offset * 4 + 3] = 255;
  52. }
  53. int main()
  54. {
  55. CPUBitmap bitmap(DIM, DIM);
  56. unsigned char* dev_bitmap;
  57. //在GPU中分配空间
  58. HANDLE_ERROR(cudaMalloc((void**)&dev_bitmap, bitmap.image_size()));
  59. dim3 grid(DIM, DIM); //dim3结构体
  60. kernel <<<grid, 1 >>> (dev_bitmap); //一个线程块中的线程网络1000x1000
  61. HANDLE_ERROR(cudaMemcpy(bitmap.get_ptr(), dev_bitmap, bitmap.image_size(), cudaMemcpyDeviceToHost)); //将dev_bitmap中的内容从device拷贝到cpu中
  62. bitmap.display_and_exit();
  63. HANDLE_ERROR(cudaFree(dev_bitmap));
  64. }


参考资料

详解 CUDA By Example 中的 Julia Set 绘制GPU优化的更多相关文章

  1. Scala 深入浅出实战经典 第61讲:Scala中隐式参数与隐式转换的联合使用实战详解及其在Spark中的应用源码解析

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载: 百度云盘:http://pan.baidu.com/s/1c0noOt ...

  2. Scala 深入浅出实战经典 第60讲:Scala中隐式参数实战详解以及在Spark中的应用源码解析

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  3. 详解OJ(Online Judge)中PHP代码的提交方法及要点【举例:ZOJ 1001 (A + B Problem)】

    详解OJ(Online Judge)中PHP代码的提交方法及要点 Introduction of How to submit PHP code to Online Judge Systems  Int ...

  4. 详解Linux下iptables中的DNAT与SNAT设置(转)

    详解Linux下iptables中的DNAT与SNAT设置 这篇文章主要介绍了Linux下iptables中的DNAT与SNAT设置,是Linux网络配置中的基础知识,需要的朋友可以参考下   原文连 ...

  5. Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制

    Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制 JAVA 中原生的 socket 通信机制 摘要:本文属于原创,欢迎转载,转载请保留出处:https://github.co ...

  6. 详解在Linux系统中安装Tomcat

    本文以在CentOS 7.6中安装Tomcat8.5为例进行安装,其他系统和版本都是大同小异的. 安装JDK 安装Tomcat之前,需要先安装JDK,可以参看之前的文章详解在Linux系统中安装JDK ...

  7. 详解如何在CentOS7中使用Nginx和PHP7-FPM安装Nextcloud

    转载地址:https://www.jb51.net/article/109382.htm 这篇文章主要介绍了详解如何在CentOS7中使用Nginx和PHP7-FPM安装Nextcloud,会通过 N ...

  8. 详解如何在Laravel中增加自定义全局函数

    http://www.php.cn/php-weizijiaocheng-383928.html 如何在Laravel中增加自定义全局函数?在我们的应用里经常会有一些全局都可能会用的函数,我们应该怎么 ...

  9. 第7.18节 案例详解:Python类中装饰器@staticmethod定义的静态方法

    第7.18节 案例详解:Python类中装饰器@staticmethod定义的静态方法 上节介绍了Python中类的静态方法,本节将结合案例详细说明相关内容. 一.    案例说明 本节定义了类Sta ...

随机推荐

  1. git命令清单 摘自 阮老师

    常用 Git 命令清单   作者: 阮一峰 日期: 2015年12月 9日 我每天使用 Git ,但是很多命令记不住. 一般来说,日常使用只要记住下图6个命令,就可以了.但是熟练使用,恐怕要记住60- ...

  2. shellcode 反汇编,模拟运行以及调试方法

    onlinedisassembler https://onlinedisassembler.com 在线反汇编工具,类似于lda.功能比较单一. Any.run 等平台在线分析 将shellcode保 ...

  3. num13---外观模式/过程模式

    假设家庭影院有一系列设备,每个设备都有各种开闭等功能性方法,使用家庭影院功能的时候,需要进行各个设备的一系列操作,繁琐麻烦. 现在提供一个外观类,在里面定义操作流程,客户端只需要和外观类进行接口交互即 ...

  4. 【TensorFlow】TensorFlow基础 —— 模型的保存读取与可视化方法总结

    TensorFlow提供了一个用于保存模型的工具以及一个可视化方案 这里使用的TensorFlow为1.3.0版本 一.保存模型数据 模型数据以文件的形式保存到本地: 使用神经网络模型进行大数据量和复 ...

  5. TCP三次握手四次挥手过程梳理

    1. 数据传输的大致示意图 1.1 TCP数据报文首部内部 1.2 TCP连接的几种状态说明 即命令 netstat 结果中的所有状态: 2. TCP连接建立的全过程 2.1 TCP三次握手建立TCP ...

  6. C#设计模式学习笔记:(12)代理模式

    本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7814004.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲结构型设计模式的第七个模式,也是 ...

  7. springcloud vue.js 前后分离 微服务 分布式 activiti工作流 集成代码生成器 shiro权限

    1.代码生成器: [正反双向](单表.主表.明细表.树形表,快速开发利器)freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本.处理类.service等完整模块2. ...

  8. SpringBoot安全管理--(二)基于数据库的认证

    简介: 上篇文章向读者介绍的认证数据都是定义在内存中的,在真实项目中,用户的基本信息以及角色等都存储在数据库中,因此需要从数据库中获取数据进行认证. 开始: 首先建表并且插入数据: pom.xml & ...

  9. iOS开发 - 在SwiftUI中显示模态视图

    在SwiftUI中显示模态视图 简介 这里教大家如何弹出一个简单的模态视图.分别有两个页面,ContentView和GCPresentedView,以下对应简称为A和B.我们要做的是在A视图中点击按钮 ...

  10. Hadoop架构及集群

    Hadoop是一个由Apache基金会所开发的分布式基础架构,Hadoop的框架最核心的设计就是:HDFS和MapReduce.HDFS为海量的数据提供了存储,而MapReduce则为海量的数据提供了 ...