CUDA by example Chapter7 纹理内存

VS2017 CUDA编程学习10:纹理内存 文章目录前言1. 纹理内存的理解2. C++ CUDA实现常量内存使用3. 执行结果总结学习资料 VS2017 CUDA编程学习1:CUDA编程两变量加法运算 VS2017 CUDA编程学习2:在GPU上执行线程 VS2017 CUDA编程学习3:CUDA获取设备上属性信息 VS2017 CUDA编程学习4:CUDA并行处理初探 - 向量加法实现 VS2017 CUDA编程学习5:CUDA并行执行-线程 VS2017 CUDA编程学习6: GPU存储器架构 VS2017 CUDA编程学习7:线程同步-共享内 阅读详情

纹理内存简介

和常量内存一样,纹理内存是另一种类型的只读内存。纹理内存是专门为那些在内存访问模式中存在大量空间局部性的图形应用程序而设计的。假如在某个计算应用程序中,一个线程读取的位置与邻近线程读取的位置"非常接近",使用纹理内存将会减少内存通信量,从而提高性能。
在这里插入图片描述

热传导模拟

简单的传热模型

假设一个矩形网格,热源分布如下。假设热源单元本身的温度保持不变,热量可以在相邻单元之间流动,从高温单元传导到低温单元。
在这里插入图片描述
温度更新的计算方法:
将单元与其邻接单元的温差加起来,然后加上原有温度,等于新时刻的温度:
TNEW = TOLD+sum_NEIGHBOR(k(TNEIGHBOR-TOLD))
由于邻接单元只有上下左右四个,将上式化简,得到:
TNEW=TOLD+k(TTOP+TBOTTOm+TLEFT+TRIGHT-4TOLD)

代码中温度更新的计算

更新流程:

  • 给定包含初始温度的网格,它的大部分单元都是0,少部分是初始温度值。将其中作为热源的初始温度值复制到当前时间的网格对应单元中。确保"加热单元将保持恒温",这个复制操作时在copy_const_kernal()中执行的。
  • 给定一个输入温度网格,根据温度更新的公式计算输出温度网格。这个更新操作是在blend_kernal()中执行的。
  • 将输入温度网格和输出温度网格交换,为下一个步骤的计算做好准备。当模拟下一个时间步时,步骤2中计算得到的输出温度网格将成为步骤1中的输入温度网格。

GPU不使用纹理内存的热传导模拟计算

完整代码

// 代码7.3不使用纹理内存的热传导模型计算
//时间:2019.07.28
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <iostream>
#include "cpu_anim.h"
#include "book.h"

#define DIM 1024
#define SPEED 0.25f
#define PI 3.1415926535897932f
#define MAX_TEMP 1.0f
#define MIN_TEMP 0.0001f



//更新函数中需要的全局变量
struct DataBlock
{
	unsigned char *output_bitmap;
	float *dev_inSrc;
	float *dev_outSrc;
	float *dev_constSrc;
	CPUAnimBitmap *bitmap;

	cudaEvent_t start, stop;
	float totalTime;
	float frames;
};

__global__ void copy_const_kernal(float *iptr, const float *cptr)
{
	//将threadIdx/blockIdx映射到像素位置
	int x = threadIdx.x + blockIdx.x*blockDim.x;
	int y = threadIdx.y + blockIdx.y*blockDim.y;
	int offset = x + y*blockDim.x*gridDim.x;

	if (cptr[offset] != 0)iptr[offset] = cptr[offset];

}

__global__ void blend_kernal(float *outSrc, const float *inSrc)
{
	//将threadIdx/blockIdx映射到像素位置
	int x = threadIdx.x + blockIdx.x*blockDim.x;
	int y = threadIdx.y + blockIdx.y*blockDim.y;
	int offset = x + y*blockDim.x*gridDim.x;

	int left = offset - 1;
	int right = offset + 1;
	if (x == 0)left++;
	if (x == DIM - 1)right--;

	int top = offset - DIM;
	int bottom = offset + DIM;
	if (y == 0)top += DIM;
	if (y == DIM - 1)bottom -= DIM;

	outSrc[offset] = inSrc[offset] + SPEED*(inSrc[top] + inSrc[bottom] + inSrc[left] + inSrc[right] - inSrc[offset] * 4);

}


//在swap这里栽了两天的跟头
void swap(float **a, float **b)
{
	float *c;
	c = *a;
	*a = *b;
	*b = c;
}



void anim_gpu(DataBlock *d, int ticks)
{
	cudaEventRecord(d->start, 0);
	dim3 grids(DIM / 16, DIM / 16);
	dim3 blocks(16, 16);
	CPUAnimBitmap *bitmap = d->bitmap;
	float *c;
	for (int i = 0; i < 90; i++)
	{
		//printf("faf");
		copy_const_kernal << <grids, blocks >> > ( d->dev_inSrc, d->dev_constSrc);
		blend_kernal << <grids, blocks >> > ( d->dev_outSrc, d->dev_inSrc );

		swap(&d->dev_inSrc,&d->dev_outSrc);
	}
	//将float数值映射成颜色,以便用图像显示它
	float_to_color << <grids, blocks >> >(d->output_bitmap,d->dev_inSrc);
	cudaMemcpy(bitmap->get_ptr(), d->output_bitmap, bitmap->image_size(), cudaMemcpyDeviceToHost);
	cudaEventRecord(d->stop,0);
	cudaEventSynchronize(d->stop);
	float elapsedTime;
	cudaEventElapsedTime(&elapsedTime, d->start, d->stop);
	d->totalTime += elapsedTime;
	++d->frames;
	printf("Average Time per frame:%3.1fms\n", d->totalTime / d->frames);
}

void anim_exit(DataBlock *d)
{
	cudaFree(d->dev_constSrc);
	cudaFree(d->dev_inSrc);
	cudaFree(d->dev_outSrc);

	cudaEventDestroy(d->start);
	cudaEventDestroy(d->stop);
}

int main()
{
	DataBlock data;
	CPUAnimBitmap bitmap(DIM, DIM, &data);
	data.bitmap = &bitmap;
	data.totalTime = 0;
	data.frames = 0;
	cudaEventCreate(&data.start);
	cudaEventCreate(&data.stop);
	cudaMalloc((void **)&data.output_bitmap, bitmap.image_size());
	cudaMalloc((void**)&data.dev_constSrc, bitmap.image_size());
	cudaMalloc((void **)&data.dev_inSrc, bitmap.image_size());
	cudaMalloc((void **)&data.dev_outSrc, bitmap.image_size());

	//在CPU上分配临时内存,对其填充一些内容,用于初始化data.dev_constSrc和data.dev_inSrc
	float *temp = (float *)malloc(bitmap.image_size());
	for (int i = 0; i < DIM*DIM; i++)
	{
		temp[i] = 0;
		int x = i % DIM;
		int y = i / DIM;
		if ((x>300) && (x<600) && (y>310) && (y < 601))
		{
			temp[i] = MAX_TEMP;
		}
	}
	temp[DIM * 100 + 100] = (MAX_TEMP + MIN_TEMP) / 2;
	temp[DIM * 700 + 100] = MIN_TEMP;
	temp[DIM * 300 + 300] = MIN_TEMP;
	temp[DIM * 200 + 700] = MIN_TEMP;
	for (int y = 800; y < 900; y++)
	{
		for (int x = 400; x < 500; x++)
		{
			temp[x + y*DIM] = MIN_TEMP;
		}
	}
	//用当前填充的内容初始化data.dev_constSrc
	cudaMemcpy(data.dev_constSrc, temp, bitmap.image_size(), cudaMemcpyHostToDevice);

	//继续向temp中填充一些内容
	for (int y = 800; y < DIM; y++)
	{
		for (int x = 0; x < 200; x++)
		{
			temp[x + y*DIM] = MAX_TEMP;
		}
	}
	//用给当前填充的内容初始化data.dev_inSrc
	cudaMemcpy(data.dev_inSrc, temp, bitmap.image_size(), cudaMemcpyHostToDevice);

	//释放CPU端的临时内存
	free(temp);
	//用anim_gpu生成动画的每一帧,用anim_exit退出动画显示并释放内存
	bitmap.anim_and_exit((void(*) (void *, int))anim_gpu, (void(*)(void *))anim_exit);
}

运行结果
在这里插入图片描述
在这里插入图片描述
需要极其注意,更新步骤中的第三步,交换输入网格和输出网格:
因为dev_inSrc和dev_outSrc分别是两幅图像的入口指针,将二者交换只需要:

float *swap;
swap = dev_inSrc;
dev_inSrc = dev_outSrc;
dev_outSrc = swap;

但是,如果使用函数swap来完成这个工作,由于函数中传入的是形参,形参的改变并不会改变传入参数的原始值,因此我们需要将&dev_inSrc和&dev_outSrc传入swap函数中,才能完成交换任务

//在swap这里栽了两天的跟头
void swap(float **a, float **b)
{
	float *c;
	c = *a;
	*a = *b;
	*b = c;
}

//使用方法
swap(&d->dev_inSrc,&d->dev_outSrc);

GPU使用一维纹理内存的热传导模拟计算

1. 纹理内存的使用场景
在温度更新计算的内存访问模式中存在着巨大的内存空间局部性,这种访问模式可以通过GPU纹理内存来加速。
2.一维纹理内存变量引用的声明

//声明纹理内存变量的引用,这些变量将位于GPU上
texture<float> texConstSrc;
texture<float> texIn;
texture<float> texOut;

3.一维纹理内存引用变量与实际内存缓冲区的绑定
通过cudaBindTexture()可以将纹理内存引用变量与内存缓冲区进行绑定。

	cudaMalloc((void **)&data.output_bitmap, bitmap.image_size());
	cudaMalloc((void**)&data.dev_constSrc, bitmap.image_size());
	cudaMalloc((void **)&data.dev_inSrc, bitmap.image_size());
	cudaMalloc((void **)&data.dev_outSrc, bitmap.image_size());

	//分配内存之后,需要将这些变量绑定到之前声明的纹理引用上去
	cudaBindTexture(NULL, texConstSrc, data.dev_constSrc, bitmap.image_size());
	cudaBindTexture(NULL, texIn, data.dev_inSrc,  bitmap.image_size());
	cudaBindTexture(NULL, texOut, data.dev_outSrc,  bitmap.image_size());

4.读取一维纹理内存方法
使用tex1Dfetch()读取一维纹理内存,传给blend_kernal的dstOut是一个bool变量,用于指明读取哪一个缓冲区作为输入。

__global__ void blend_kernal(float *dst, bool dstOut)
{
	//将threadIdx/blockIdx映射到像素位置
	int x = threadIdx.x + blockIdx.x*blockDim.x;
	int y = threadIdx.y + blockIdx.y*blockDim.y;
	int offset = x + y*blockDim.x*gridDim.x;

	int left = offset - 1;
	int right = offset + 1;
	if (x == 0)left++;
	if (x == DIM - 1)right--;

	int top = offset - DIM;
	int bottom = offset + DIM;
	if (y == 0)top += DIM;
	if (y == DIM - 1)bottom -= DIM;

	float t, b, l, r, c;
	if (dstOut)
	{
		t = tex1Dfetch(texIn,top);
		b = tex1Dfetch(texIn, bottom);
		l = tex1Dfetch(texIn, left);
		r = tex1Dfetch(texIn, right);
		c = tex1Dfetch(texIn, offset);
	}
	else
	{
		t = tex1Dfetch(texOut, top);
		b = tex1Dfetch(texOut, bottom);
		l = tex1Dfetch(texOut, left);
		r = tex1Dfetch(texOut, right);
		c = tex1Dfetch(texOut, offset);
	}

	dst[offset] = c + SPEED*(t + b + l + r - 4 * c);
}

5.完整代码

// 代码7.3.4使用一维纹理内存的热传导模型计算
//时间:2019.07.29
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <iostream>
#include "cpu_anim.h"
#include "cuda.h"
#include "book.h"

#define DIM 1024
#define SPEED 0.25f
#define PI 3.1415926535897932f
#define MAX_TEMP 1.0f
#define MIN_TEMP 0.0001f

//声明纹理内存变量的引用,这些变量将位于GPU上
texture<float> texConstSrc;
texture<float> texIn;
texture<float> texOut;




//更新函数中需要的全局变量
struct DataBlock
{
	unsigned char *output_bitmap;
	float *dev_inSrc;
	float *dev_outSrc;
	float *dev_constSrc;
	CPUAnimBitmap *bitmap;

	cudaEvent_t start, stop;
	float totalTime;
	float frames;
};

__global__ void copy_const_kernal(float *iptr)
{
	//将threadIdx/blockIdx映射到像素位置
	int x = threadIdx.x + blockIdx.x*blockDim.x;
	int y = threadIdx.y + blockIdx.y*blockDim.y;
	int offset = x + y*blockDim.x*gridDim.x;

	float c = tex1Dfetch(texConstSrc, offset);
	if (c != 0)iptr[offset] = c;

}

__global__ void blend_kernal(float *dst, bool dstOut)
{
	//将threadIdx/blockIdx映射到像素位置
	int x = threadIdx.x + blockIdx.x*blockDim.x;
	int y = threadIdx.y + blockIdx.y*blockDim.y;
	int offset = x + y*blockDim.x*gridDim.x;

	int left = offset - 1;
	int right = offset + 1;
	if (x == 0)left++;
	if (x == DIM - 1)right--;

	int top = offset - DIM;
	int bottom = offset + DIM;
	if (y == 0)top += DIM;
	if (y == DIM - 1)bottom -= DIM;

	float t, b, l, r, c;
	if (dstOut)
	{
		t = tex1Dfetch(texIn,top);
		b = tex1Dfetch(texIn, bottom);
		l = tex1Dfetch(texIn, left);
		r = tex1Dfetch(texIn, right);
		c = tex1Dfetch(texIn, offset);
	}
	else
	{
		t = tex1Dfetch(texOut, top);
		b = tex1Dfetch(texOut, bottom);
		l = tex1Dfetch(texOut, left);
		r = tex1Dfetch(texOut, right);
		c = tex1Dfetch(texOut, offset);
	}

	dst[offset] = c + SPEED*(t + b + l + r - 4 * c);
}





void anim_gpu(DataBlock *d, int ticks)
{
	cudaEventRecord(d->start, 0);
	dim3 grids(DIM / 16, DIM / 16);
	dim3 blocks(16, 16);
	CPUAnimBitmap *bitmap = d->bitmap;

	//由于tex是全局并且是有界的,因此我们必须通过一个标志来来选择每次迭代中哪个是输入/输出
	volatile bool dstOut = true;
	for (int i = 0; i < 90; i++)
	{
		float *in, *out;
		if (dstOut)
		{
			in = d->dev_inSrc;
			out = d->dev_outSrc;
		}
		else
		{
			in = d->dev_outSrc;
			out = d->dev_inSrc;
		}
		copy_const_kernal << <grids, blocks >> > (in);
		blend_kernal << <grids, blocks >> > (out,dstOut);
		dstOut = !dstOut;
	}
	//将float数值映射成颜色,以便用图像显示它
	float_to_color << <grids, blocks >> >(d->output_bitmap, d->dev_inSrc);
	cudaMemcpy(bitmap->get_ptr(), d->output_bitmap, bitmap->image_size(), cudaMemcpyDeviceToHost);
	cudaEventRecord(d->stop, 0);
	cudaEventSynchronize(d->stop);
	float elapsedTime;
	cudaEventElapsedTime(&elapsedTime, d->start, d->stop);
	d->totalTime += elapsedTime;
	++d->frames;
	printf("Average Time per frame:%3.1fms\n", d->totalTime / d->frames);
}

void anim_exit(DataBlock *d)
{
	cudaUnbindTexture(texIn);
	cudaUnbindTexture(texOut);
	cudaUnbindTexture(texConstSrc);

	cudaFree(d->dev_constSrc);
	cudaFree(d->dev_inSrc);
	cudaFree(d->dev_outSrc);

	cudaEventDestroy(d->start);
	cudaEventDestroy(d->stop);
}

int main()
{
	DataBlock data;
	CPUAnimBitmap bitmap(DIM, DIM, &data);
	data.bitmap = &bitmap;
	data.totalTime = 0;
	data.frames = 0;
	cudaEventCreate(&data.start);
	cudaEventCreate(&data.stop);
	cudaMalloc((void **)&data.output_bitmap, bitmap.image_size());
	cudaMalloc((void**)&data.dev_constSrc, bitmap.image_size());
	cudaMalloc((void **)&data.dev_inSrc, bitmap.image_size());
	cudaMalloc((void **)&data.dev_outSrc, bitmap.image_size());

	//分配内存之后,需要将这些变量绑定到之前声明的纹理引用上去
	//cudaChannelFormatDesc desc = cudaCreateChannelDesc<float>();
	cudaBindTexture(NULL, texConstSrc, data.dev_constSrc, bitmap.image_size());
	cudaBindTexture(NULL, texIn, data.dev_inSrc,  bitmap.image_size());
	cudaBindTexture(NULL, texOut, data.dev_outSrc,  bitmap.image_size());


	//在CPU上分配临时内存,对其填充一些内容,用于初始化data.dev_constSrc和data.dev_inSrc
	float *temp = (float *)malloc(bitmap.image_size());
	for (int i = 0; i < DIM*DIM; i++)
	{
		temp[i] = 0;
		int x = i % DIM;
		int y = i / DIM;
		if ((x>300) && (x<600) && (y>310) && (y < 601))
		{
			temp[i] = MAX_TEMP;
		}
	}
	temp[DIM * 100 + 100] = (MAX_TEMP + MIN_TEMP) / 2;
	temp[DIM * 700 + 100] = MIN_TEMP;
	temp[DIM * 300 + 300] = MIN_TEMP;
	temp[DIM * 200 + 700] = MIN_TEMP;
	for (int y = 800; y < 900; y++)
	{
		for (int x = 400; x < 500; x++)
		{
			temp[x + y*DIM] = MIN_TEMP;
		}
	}
	//用当前填充的内容初始化data.dev_constSrc
	cudaMemcpy(data.dev_constSrc, temp, bitmap.image_size(), cudaMemcpyHostToDevice);

	//继续向temp中填充一些内容
	for (int y = 800; y < DIM; y++)
	{
		for (int x = 0; x < 200; x++)
		{
			temp[x + y*DIM] = MAX_TEMP;
		}
	}
	//用给当前填充的内容初始化data.dev_inSrc
	cudaMemcpy(data.dev_inSrc, temp, bitmap.image_size(), cudaMemcpyHostToDevice);

	//释放CPU端的临时内存
	free(temp);
	//用anim_gpu生成动画的每一帧,用anim_exit退出动画显示并释放内存
	bitmap.anim_and_exit((void(*) (void *, int))anim_gpu, (void(*)(void *))anim_exit);
}

6.运行结果
在这里插入图片描述
在这里插入图片描述
bang!!!性能并没有得到提升,反而急剧恶化,不知所措,如果有哪位同学遇到跟我同样的问题,欢迎联系我讨论

GPU使用二维纹理内存的热传导模拟计算

1. 二维纹理内存变量引用的声明

//声明纹理内存变量的引用,这些变量将位于GPU上
texture<float,2> texConstSrc;
texture<float,2> texIn;
texture<float,2> texOut;

2.二维纹理内存引用变量与实际内存缓冲区的绑定
通过cudaBindTexture2D()可以将纹理内存引用变量与内存缓冲区进行绑定。
绑定二维纹理时,CUDA运行时要求提供一个cudaChannelFormatDesc,保持默认设置就可以了。

	cudaMalloc((void **)&data.output_bitmap, bitmap.image_size());
	cudaMalloc((void**)&data.dev_constSrc, bitmap.image_size());
	cudaMalloc((void **)&data.dev_inSrc, bitmap.image_size());
	cudaMalloc((void **)&data.dev_outSrc, bitmap.image_size());

	//分配内存之后,需要将这些变量绑定到之前声明的纹理引用上去
	cudaChannelFormatDesc desc = cudaCreateChannelDesc<float>();
	cudaBindTexture2D(NULL, texConstSrc, data.dev_constSrc, desc, DIM, DIM, sizeof(float)*DIM);
	cudaBindTexture2D(NULL, texIn, data.dev_inSrc, desc, DIM, DIM, sizeof(float)*DIM);
	cudaBindTexture2D(NULL, texOut, data.dev_outSrc, desc, DIM, DIM, sizeof(float)*DIM);

3.读取二维纹理内存方法
通过tex2D()读取二维纹理内存

__global__ void blend_kernal(float *dst, bool dstOut)
{
	//将threadIdx/blockIdx映射到像素位置
	int x = threadIdx.x + blockIdx.x*blockDim.x;
	int y = threadIdx.y + blockIdx.y*blockDim.y;
	int offset = x + y*blockDim.x*gridDim.x;

	int left = offset - 1;
	int right = offset + 1;
	if (x == 0)left++;
	if (x == DIM - 1)right--;

	int top = offset - DIM;
	int bottom = offset + DIM;
	if (y == 0)top += DIM;
	if (y == DIM - 1)bottom -= DIM;

	float t, b, l, r, c;
	if (dstOut)
	{
		t = tex2D(texIn, x, y - 1);
		l = tex2D(texIn, x - 1, y);
		c = tex2D(texIn, x, y);
		r = tex2D(texIn, x + 1, y);
		b = tex2D(texIn, x, y + 1);
	}
	else
	{
		t = tex2D(texOut, x, y - 1);
		l = tex2D(texOut, x - 1, y);
		c = tex2D(texOut, x, y);
		r = tex2D(texOut, x + 1, y);
		b = tex2D(texOut, x, y + 1);
	}

	dst[offset] = c + SPEED*(t + b + l + r - 4 * c);
}

4.完整代码

// 代码7.3.4使用二维纹理内存的热传导模型计算
//时间:2019.07.29
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <iostream>
#include "cpu_anim.h"
#include "cuda.h"
#include "book.h"

#define DIM 1024
#define SPEED 0.25f
#define PI 3.1415926535897932f
#define MAX_TEMP 1.0f
#define MIN_TEMP 0.0001f

//声明纹理内存变量的引用,这些变量将位于GPU上
texture<float,2> texConstSrc;
texture<float,2> texIn;
texture<float,2> texOut;




//更新函数中需要的全局变量
struct DataBlock
{
	unsigned char *output_bitmap;
	float *dev_inSrc;
	float *dev_outSrc;
	float *dev_constSrc;
	CPUAnimBitmap *bitmap;

	cudaEvent_t start, stop;
	float totalTime;
	float frames;
};

__global__ void copy_const_kernal(float *iptr)
{
	//将threadIdx/blockIdx映射到像素位置
	int x = threadIdx.x + blockIdx.x*blockDim.x;
	int y = threadIdx.y + blockIdx.y*blockDim.y;
	int offset = x + y*blockDim.x*gridDim.x;

	float c = tex2D(texConstSrc, x, y);
	if (c != 0)iptr[offset] = c;

}

__global__ void blend_kernal(float *dst, bool dstOut)
{
	//将threadIdx/blockIdx映射到像素位置
	int x = threadIdx.x + blockIdx.x*blockDim.x;
	int y = threadIdx.y + blockIdx.y*blockDim.y;
	int offset = x + y*blockDim.x*gridDim.x;

	int left = offset - 1;
	int right = offset + 1;
	if (x == 0)left++;
	if (x == DIM - 1)right--;

	int top = offset - DIM;
	int bottom = offset + DIM;
	if (y == 0)top += DIM;
	if (y == DIM - 1)bottom -= DIM;

	float t, b, l, r, c;
	if (dstOut)
	{
		t = tex2D(texIn, x, y - 1);
		l = tex2D(texIn, x - 1, y);
		c = tex2D(texIn, x, y);
		r = tex2D(texIn, x + 1, y);
		b = tex2D(texIn, x, y + 1);
	}
	else
	{
		t = tex2D(texOut, x, y - 1);
		l = tex2D(texOut, x - 1, y);
		c = tex2D(texOut, x, y);
		r = tex2D(texOut, x + 1, y);
		b = tex2D(texOut, x, y + 1);
	}

	dst[offset] = c + SPEED*(t + b + l + r - 4 * c);
}





void anim_gpu(DataBlock *d, int ticks)
{
	cudaEventRecord(d->start, 0);
	dim3 grids(DIM / 16, DIM / 16);
	dim3 blocks(16, 16);
	CPUAnimBitmap *bitmap = d->bitmap;

	//由于tex是全局并且是有界的,因此我们必须通过一个标志来来选择每次迭代中哪个是输入/输出
	volatile bool dstOut = true;
	for (int i = 0; i < 90; i++)
	{
		float *in, *out;
		if (dstOut)
		{
			in = d->dev_inSrc;
			out = d->dev_outSrc;
		}
		else
		{
			in = d->dev_outSrc;
			out = d->dev_inSrc;
		}
		copy_const_kernal << <grids, blocks >> > (in);
		blend_kernal << <grids, blocks >> > (out, dstOut);
		dstOut = !dstOut;
	}
	//将float数值映射成颜色,以便用图像显示它
	float_to_color << <grids, blocks >> >(d->output_bitmap, d->dev_inSrc);
	cudaMemcpy(bitmap->get_ptr(), d->output_bitmap, bitmap->image_size(), cudaMemcpyDeviceToHost);
	cudaEventRecord(d->stop, 0);
	cudaEventSynchronize(d->stop);
	float elapsedTime;
	cudaEventElapsedTime(&elapsedTime, d->start, d->stop);
	d->totalTime += elapsedTime;
	++d->frames;
	printf("Average Time per frame:%3.1fms\n", d->totalTime / d->frames);
}

void anim_exit(DataBlock *d)
{
	cudaUnbindTexture(texIn);
	cudaUnbindTexture(texOut);
	cudaUnbindTexture(texConstSrc);

	cudaFree(d->dev_constSrc);
	cudaFree(d->dev_inSrc);
	cudaFree(d->dev_outSrc);

	cudaEventDestroy(d->start);
	cudaEventDestroy(d->stop);
}

int main()
{
	DataBlock data;
	CPUAnimBitmap bitmap(DIM, DIM, &data);
	data.bitmap = &bitmap;
	data.totalTime = 0;
	data.frames = 0;
	cudaEventCreate(&data.start);
	cudaEventCreate(&data.stop);
	cudaMalloc((void **)&data.output_bitmap, bitmap.image_size());
	cudaMalloc((void**)&data.dev_constSrc, bitmap.image_size());
	cudaMalloc((void **)&data.dev_inSrc, bitmap.image_size());
	cudaMalloc((void **)&data.dev_outSrc, bitmap.image_size());

	//分配内存之后,需要将这些变量绑定到之前声明的纹理引用上去
	cudaChannelFormatDesc desc = cudaCreateChannelDesc<float>();
	cudaBindTexture2D(NULL, texConstSrc, data.dev_constSrc, desc, DIM, DIM, sizeof(float)*DIM);
	cudaBindTexture2D(NULL, texIn, data.dev_inSrc, desc, DIM, DIM, sizeof(float)*DIM);
	cudaBindTexture2D(NULL, texOut, data.dev_outSrc, desc, DIM, DIM, sizeof(float)*DIM);


	//在CPU上分配临时内存,对其填充一些内容,用于初始化data.dev_constSrc和data.dev_inSrc
	float *temp = (float *)malloc(bitmap.image_size());
	for (int i = 0; i < DIM*DIM; i++)
	{
		temp[i] = 0;
		int x = i % DIM;
		int y = i / DIM;
		if ((x>300) && (x<600) && (y>310) && (y < 601))
		{
			temp[i] = MAX_TEMP;
		}
	}
	temp[DIM * 100 + 100] = (MAX_TEMP + MIN_TEMP) / 2;
	temp[DIM * 700 + 100] = MIN_TEMP;
	temp[DIM * 300 + 300] = MIN_TEMP;
	temp[DIM * 200 + 700] = MIN_TEMP;
	for (int y = 800; y < 900; y++)
	{
		for (int x = 400; x < 500; x++)
		{
			temp[x + y*DIM] = MIN_TEMP;
		}
	}
	//用当前填充的内容初始化data.dev_constSrc
	cudaMemcpy(data.dev_constSrc, temp, bitmap.image_size(), cudaMemcpyHostToDevice);

	//继续向temp中填充一些内容
	for (int y = 800; y < DIM; y++)
	{
		for (int x = 0; x < 200; x++)
		{
			temp[x + y*DIM] = MAX_TEMP;
		}
	}
	//用给当前填充的内容初始化data.dev_inSrc
	cudaMemcpy(data.dev_inSrc, temp, bitmap.image_size(), cudaMemcpyHostToDevice);

	//释放CPU端的临时内存
	free(temp);
	//用anim_gpu生成动画的每一帧,用anim_exit退出动画显示并释放内存
	bitmap.anim_and_exit((void(*) (void *, int))anim_gpu, (void(*)(void *))anim_exit);
}

5.运行结果
在这里插入图片描述
在这里插入图片描述
bang!!!性能并没有得到提升,反而急剧恶化,不知所措,如果有哪位同学遇到跟我同样的问题,欢迎联系我讨论

CUDA:纹理内存的使用实例 它还指定了纹理类型为cudaTextureType1D,表示我们正在处理的数据是一维的。这个模式表示,当我们通过纹理采样器读取纹理时,返回的是单个元素值,而不是一个颜色向量。这里,我们将数据“data”绑定到了我们之前声明的texture对象“texRef”上。在这个示例中,我们生成了一个256元的正弦波,并将其绑定到纹理内存中。通过使用纹理内存,我们可以以高效的方式访问只读数据,并利用硬件加速器来提高应用程序的性能。一旦我们将数据绑定到了texture对象上,我们就可以在CUDA内核函数中使用它了。 阅读详情

相关推荐

告别串口打印:手把手教你用Qt Creator远程调试i.MX6开发板(附gdbserver配置)

本文详细介绍了如何使用Qt Creator配合gdbserver实现i.MX6等ARM开发板的远程调试,告别传统的串口打印调试方式。通过图形化界面设置断点、监控变量,显著提升嵌入式开发效率,适用于各类ARM架构开发板的调试需求。

weixin_30781775的博客 217

[菜鸟每天来段CUDA_C]CUDA实现简单热传导动态模拟

本文利用CUDA实现简单二维平面上的热传导模拟。假设有一个矩形房间,将其分成一个网格,在网格中随机散布一些热源,热源有不同的固定温度,然后就可以计算网格中每个单元的温度随时间的变化情况。本文将热传导模型做如下简化:某单元的新时刻温度等于原有温度加其与邻接单元的温差,邻接单元取上下左右四个单元。

Running Jonny 3641

AHB2eflash 控制器设计笔记

① SRAM② DRAM③ SSD④ SATA⑤ U 盘⑥ 移动硬盘⑦ 机械磁盘eflash。

weixin_46220498的博客 3078

CUDA By Example(六)——纹理内存

CUDA C中纹理内存使用的说明,并以热传导模拟为例

hhhcbw的博客,欢迎各位来访 1568

告别Quartus II的漫长等待:用VSCode+iverilog+GTKWave搭建你的轻量级Verilog仿真环境(2024保姆级教程)

本文详细介绍了如何利用VSCode、iverilog和GTKWave构建高效的Verilog/SystemVerilog开发环境,替代传统的Quartus II和ModelSim工具。通过2024年最新的保姆级教程,帮助开发者实现秒级启动、低资源消耗的轻量级仿真环境,显著提升数字电路设计的开发效率和调试体验。

weixin_33690963的博客 561

基于ADS的低噪声放大电路设计

1. 低噪声放大器设计理论基础 1.1 低噪声放大器在通信系统中的作用 低噪声放大器的主要作用是放大天线从空中接收到的微弱信号,减小噪声干扰,以供系统解调出所需的信息数据。当今,人们对于各种无线通信工具的要求越来越高,如功率辐射要小、作用距离要远、覆盖范围要广等,这就对系统的接收灵敏度提出了更高的要求,系统接收灵敏度的计算公式为: Smin⁡=−144(dBmHz)+NF+10lg⁡BW(MHz)+SN(dB) {S_{\min }} = - 144\left( {\frac{{{\rm{dBm}}}}{

ASH_GUARDIAN的博客 4万+

简单的传热模型的动画模拟

/* 简单的二维热传导模拟: 首先,假设有一个矩形房间,将其分成一个网格,在网格中随机散布一些热源, 他们有着不同的固定温度,在给定了矩形网格及热源分布后可以计算网格中每 个单元的温度随时间的变化情况,为了简单热源单元本身的温度将保持不变, 在时间递进的每个步骤中,假设热量在某个单干及其邻接单元之间流动,如果 某个单元的临接单元的温度更高,那么热量将从临接单元传导到该单元,相反的 如

wufenxia的专栏 4375

01 ArcGIS空间分析--水文分析--利用水文分析方法提取山谷山脊线

ArcGIS空间分析的一个特别好的分析教程是汤国安老师的空间分析的内容。 实例与练习 练习1. 利用水文分析方法提取山脊、山谷线 1. 背景:山脊线、山谷线是地形特征线,它们对地形、地貌具有一定的控制作用。它们与山顶点、谷底点以及鞍部点等一起构成了地形及其起伏变化的骨架结构。因此在数字地形分析中,山脊线和山谷线以及

Meditation 1万+

使用用一维纹理存储器的热传导模拟

#include #include "book.h" #include "cpu_anim.h" #define DIM 1024 #define PI 3.141592653f #define MAX_TEMP 1.0f #define MIN_TEMP 0.0001f #define SPEED 0.25f /*在温度更新计算的内存访问模式中存在着巨大的内存空间局部性,这种访

wufenxia的专栏 2115

DRV8711驱动器的各寄存器的介绍

drv8711驱动器

PCLintelligence的博客 1636

【AI大模型】核心基石:Transformer架构入门通俗完整解读

文章摘要: Transformer架构是AI大模型(如GPT、Llama等)的核心基石,彻底颠覆了传统RNN/LSTM的逐字计算模式,通过自注意力机制实现全局并行运算和长文本语义理解。本文用通俗语言拆解Transformer的核心模块:位置编码保留语序、多头注意力捕捉上下文关联、掩码机制确保生成逻辑、残差连接稳定训练,并搭配极简PyTorch代码演示Decoder架构的逐字生成过程。Transformer的并行性、可堆叠性和全局注意力优势,使其成为千亿参数大模型的基础。理解Transformer是掌握大模型

unber的博客 44

《CUDA By Example》【Chapter 07】纹理内存 ?

7.1 本章目标 纹理内存和常量内存一样,都是只读内存,用来减少带宽流量,提升性能。 1,了解纹理内存的特性 2,了解如何在CUDA C中使用一维纹理内存 3,了解如何在CUDA C中使用二维纹理内存 7.2 纹理内存简介(Texture Memory) 7.3 热传导模拟...

wondervictor的博客 357

基于Python的彩票数据爬虫:数据抓取与趋势分析

爬虫是一种用于从互联网上自动抓取信息的程序。在抓取彩票数据时,我们首先需要确定目标网站并获取其网页内容,接着提取彩票的开奖结果信息并保存。彩票数据通常是以HTML表格或列表的形式展示,爬虫可以利用Python的requests和来抓取静态网页,或使用Selenium来抓取动态页面。在本篇博客中,我们深入探讨了如何使用Python编写彩票数据爬虫,抓取并分析彩票开奖结果。通过Python爬虫技术,结合数据分析与可视化工具,我们能够全面分析历史开奖数据,揭示彩票号码的频率分布、趋势变化以及未来的可能走势。

2201_76125261的博客 1940

Hands-On GPU加速计算机视觉全解析:OpenCV+CUDA从入门到实战的完整路线图

如果你正在寻找一条系统学习 **GPU加速计算机视觉** 的完整路径,那么 Hands-On-GPU-Accelerated-Computer-Vision-with-OpenCV-and-CUDA 这个开源项目就是为你准备的宝藏仓库。它源自 Packt 出版的同名经典书籍,由资深计算机视觉工程师 Bhaumik Vaidya 编写,将 **OpenCV + CUDA** 双技术栈的实战代码全部开

gitblog_01053的博客 759

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

基于纹理内存的CUDA热传导模拟

原文链接 项目中有三个,第一个是全局内存,其余两个分别是基于1d和2d纹理内存。项目打包下载。 纹理内存是只读内存,与常量内存相同的是,纹理内存也缓存在芯片中,因此某些情况下,它能减少对内存的请求并提供更高效的内存宽带。纹理内存专门为那些内存访问模式中存在大量空间局部性的图形应用程序而设计的。在某个计算应用程序中,这意味着一个线程读取的位置可能与邻近线程读取的位置“非常接近”。纹理缓存为了加速...

weixin_30677475的博客 247

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

CUDA Samples: Long Vector Add

CUDA Samples: Long Vector Add

网络资源是无限的 1304

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

CUDA一维纹理内存

纹理一词来源于GPU图形世界,GPU通用并行计算“盗用”了纹理一词,定义了一个纹理内存的概念。纹理内存缓存在 设备上,在某些情况下能减少对内存的请求并降低内存带宽的使用,是专门为那些在内存访问模式中存在大量空间局部性的图形应用而设计,意味着一个线程读取的位置可能与邻近线程读取的位置“非常接近”。对于GPU内核而言,纹理内存是只读内存,并且只有通过特殊的纹理API...

weixin_30467087的博客 304

使用二维纹理内存模拟热传导

#include #include "book.h" #include "cpu_anim.h" #define DIM 1024 #define PI 3.141592653f #define MAX_TEMP 1.0f #define MIN_TEMP 0.0001f #define SPEED 0.25f /*使用二维维纹理内存*/ //在GPU上定义纹理变量 text

wufenxia的专栏 1691

CUDA总结:纹理内存

来源:《CUDA_Runtime_API》、《CUDA_C_Programming_Guide-V8.0》 纹理内存和表面内存(surface memory)实质上是全局内存的一个特殊形态,全局内存被绑定为纹理内存(表面内存),对其的读(写)操作将通过专门的texture cache(纹理缓存)进行,其实称为纹理缓存更加贴切。 纹理缓存的优势:纹理缓存具备硬件插值特性,可以实现最近邻插值和线性

Kelvin_Yan的专栏 1万+

CUDA By Examples 8 - 纹理内存Texture Memory

可以使用一维和二维纹理内存. 纹理内存是只读的.

Full_Speed_Turbo 1511

CUDA内存--纹理内存的说明与使用

纹理介绍      纹理存储器(texture memory)是一种只读存储器,由GPU用于纹理渲染的的图形专用单元发展而来,因此也提供了一些特殊功能。      纹理缓存的优势:纹理缓存具备硬件插值特性,可以实现最近邻插值和线性插值。纹理缓存针对二维空间的局部性访问进行了优化,所以通过纹理缓存访问二维矩阵的邻域会获得加速。纹理缓存不需要满足全局内存的合并访问条件。      纹理可以是一段

学习使我快乐 9297

NVIDIA CUDA 学习 (5) Texture Memory

Texture Memory纹理内存热传导模型 纹理内存 热传导模型

weixin_47658743的博客 1004

《cuda by example》 book.h 头文件解析

cpu_bitmap.h 头函数解析                blog.youkuaiyun.com/ghost129/article/details/4409565 都是一些函数,等用到的时候再过来解析,哈哈! #ifndef __BOOK_H__ #define __BOOK_H__ #include /* cuda检错程序 */ static

fulva的专栏 6167

CUDA + OpenCV实现CUDA By Example中波纹示例

参考了网上其他人的CUDA + OpenCV实现Julia Set的例子( https://blog.youkuaiyun.com/Ricardo232525/article/details/74178963),用到了波纹示例上,代码如下:#include "device_launch_parameters.h"#include "cuda_runtime.h"  #include &lt;highgui.h...

小小学渣的博客 1225

CUDA 内存模型

CUDA 内存模型 CUDA 可编程内存类型: 寄存器(Registers) 共享内存(Shared Memory) 本地内存(Local Memory) 常量内存(Constant Memory) 纹理内存(Texture Memory) 全局内存(Global Memory) 上述各种内存都有自己的作用域,生命周期和缓存行为。一个核函数中的每个线程都有自己私有的本地内存。一个线程块有自己的共享内存,对同一线程块内所有线程可见,其内容持续线程块的整个生命周期。所有线程都可以访问全局内存。所有线程都能访

A-Egoist的博客 1195

CUDA(Ⅷ):纹理内存(Texture Memory)

1.学习目标: 了解纹理内存的性能特性 了解如何在CUDA C中使用一维纹理内存 了解如何在CUDA C中使用二维纹理内存 2.背景提出: 特定环境中使用特殊的内存将极大地提升应用程序的性能。与Constant Memory相似,Texture Memory同样缓存在芯片上,只读内存,在某些情况下,能减少对内存的请求并提供更高效的内存带宽。Texture Mmeory是专门为那些在内存访...

每天进步一点点! 7386
上一篇: CUDA by example Chapter6 常量内存与事件
下一篇: CUDA by example Chapter9 原子性
Leo-Ma
博客等级 码龄11年 1701粉丝 124原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值