Textures and surfaces#
Textures and surfaces (sim only) A CPU model of the bindless texture API: cudaArray-backed storage, a channel descriptor, and texture objects carrying addressing + filtering state. MODELLED: 1-D/2-D/3-D fetches by integer or unnormalised/normalised float coordinates, all four address modes (wrap/clamp/mirror/border) and both filter modes; cudaReadModeNormalizedFloat for cudaArray-backed 8- and 16-bit integer texels; surfaces via surf1D/surf2Dread/write. NOT modelled: mipmaps, layered and cubemap textures, sRGB conversion and anisotropy — texture memory here is just an array with addressing rules, not a cache.
Defined in code/simulator.h.
This page documents 10 symbols: 1 enums, 9 functions.
Enums#
Signature |
Description |
Availability |
Location |
Example |
|---|---|---|---|---|
|
sim only |
simulator.h:2788 |
Functions#
Signature |
Description |
Availability |
Location |
Example |
|---|---|---|---|---|
|
sim only |
simulator.h:2794 |
||
|
sim only |
simulator.h:2814 |
||
|
sim only |
simulator.h:2887 |
||
|
sim only |
simulator.h:2875 |
||
|
cudaReadModeNormalizedFloat: an 8- or 16-bit integer texel is returned as a float, unsigned scaled to [0,1] and signed to [-1,1] (the real hardware conversion). |
sim only |
simulator.h:2836 |
|
|
sim only |
simulator.h:2800 |
||
|
sim only |
simulator.h:2868 |
||
|
sim only |
simulator.h:2870 |
||
|
sim only |
simulator.h:2872 |
Examples#
Code from the repository’s example corpus (code\*.cu); the highlighted line is the call site. These blocks are what the View links above open.
cudaCreateChannelDesc (test_web_cs_boxfilter.cu:206)
196 // [SIM] small integers, so the sliding-window sums stay exact and the two
197 // row passes (texture vs global) can be required to match bit for bit.
198 std::mt19937 rng(12345u);
199 std::uniform_int_distribution<int> d16(0, 15);
200 std::vector<float> hImg(nPix);
201 for (size_t i = 0; i < nPix; ++i) hImg[i] = (float)d16(rng);
202
203 // Source image in a cudaArray, plus a plain linear copy for the non-texture
204 // row pass.
205 cudaChannelFormatDesc fdesc = cudaCreateChannelDesc(32, 0, 0, 0, cudaChannelFormatKindFloat);
206 cudaArray_t d_array = nullptr;
207 check(cudaMallocArray(&d_array, &fdesc, width, height), "cudaMallocArray");
208 check(cudaMemcpy2DToArray(d_array, 0, 0, hImg.data(), width * sizeof(float),
209 width * sizeof(float), height, cudaMemcpyHostToDevice),
210 "cudaMemcpy2DToArray");
211
212 cudaResourceDesc texRes;
213 std::memset(&texRes, 0, sizeof(cudaResourceDesc));
214 texRes.resType = cudaResourceTypeArray;
215 texRes.res.array.array = d_array;
cudaCreateChannelDesc (test_web_cs_boxfilter.cu:206)
196 // [SIM] small integers, so the sliding-window sums stay exact and the two
197 // row passes (texture vs global) can be required to match bit for bit.
198 std::mt19937 rng(12345u);
199 std::uniform_int_distribution<int> d16(0, 15);
200 std::vector<float> hImg(nPix);
201 for (size_t i = 0; i < nPix; ++i) hImg[i] = (float)d16(rng);
202
203 // Source image in a cudaArray, plus a plain linear copy for the non-texture
204 // row pass.
205 cudaChannelFormatDesc fdesc = cudaCreateChannelDesc(32, 0, 0, 0, cudaChannelFormatKindFloat);
206 cudaArray_t d_array = nullptr;
207 check(cudaMallocArray(&d_array, &fdesc, width, height), "cudaMallocArray");
208 check(cudaMemcpy2DToArray(d_array, 0, 0, hImg.data(), width * sizeof(float),
209 width * sizeof(float), height, cudaMemcpyHostToDevice),
210 "cudaMemcpy2DToArray");
211
212 cudaResourceDesc texRes;
213 std::memset(&texRes, 0, sizeof(cudaResourceDesc));
214 texRes.resType = cudaResourceTypeArray;
215 texRes.res.array.array = d_array;
cudaFreeArray (test_web_cs_boxfilter.cu:268)
258 double maxRel = 0.0;
259 for (size_t i = 0; i < nPix; ++i) {
260 const double den = std::fabs(ref[i]) > 1e-6 ? std::fabs(ref[i]) : 1.0;
261 maxRel = std::max(maxRel, std::fabs((double)hOut[i] - ref[i]) / den);
262 }
263 std::printf("box filter (r=%d, %dx%d) vs direct-sum reference: max rel err = %g\n",
264 radius, width, height, maxRel);
265 if (!(maxRel < 1e-5)) g_ok = false;
266
267 check(cudaDestroyTextureObject(tex), "cudaDestroyTextureObject");
268 check(cudaFreeArray(d_array), "cudaFreeArray");
269 check(cudaFree(d_src), "cudaFree src");
270 check(cudaFree(d_temp), "cudaFree temp");
271 check(cudaFree(d_temp2), "cudaFree temp2");
272 check(cudaFree(d_dest), "cudaFree dest");
273
274 std::printf("boxFilter: %s\n", g_ok ? "PASSED" : "FAILED");
275 return g_ok ? 0 : 1;
276}
cudaMallocArray (test_web_cs_boxfilter.cu:208)
198 // row passes (texture vs global) can be required to match bit for bit.
199 std::mt19937 rng(12345u);
200 std::uniform_int_distribution<int> d16(0, 15);
201 std::vector<float> hImg(nPix);
202 for (size_t i = 0; i < nPix; ++i) hImg[i] = (float)d16(rng);
203
204 // Source image in a cudaArray, plus a plain linear copy for the non-texture
205 // row pass.
206 cudaChannelFormatDesc fdesc = cudaCreateChannelDesc(32, 0, 0, 0, cudaChannelFormatKindFloat);
207 cudaArray_t d_array = nullptr;
208 check(cudaMallocArray(&d_array, &fdesc, width, height), "cudaMallocArray");
209 check(cudaMemcpy2DToArray(d_array, 0, 0, hImg.data(), width * sizeof(float),
210 width * sizeof(float), height, cudaMemcpyHostToDevice),
211 "cudaMemcpy2DToArray");
212
213 cudaResourceDesc texRes;
214 std::memset(&texRes, 0, sizeof(cudaResourceDesc));
215 texRes.resType = cudaResourceTypeArray;
216 texRes.res.array.array = d_array;
217
218 cudaTextureDesc texDescr;
219 std::memset(&texDescr, 0, sizeof(cudaTextureDesc));
pack (test_web_pk_packsplit.cu:189)
179 cudaDeviceSynchronize();
180
181 cudaMemcpy(h_output_gpu.data(), d_output, sizeof(float) * length, cudaMemcpyDeviceToHost);
182 // CPU reference produces a compacted prefix; unused tail is undefined, so
183 // only the first (count of positives) entries are compared.
184 std::vector<float> h_output_pack(length, 0.f);
185 pack_host(h_output_pack.data(), h_input.data(), length);
186 int n_pos = 0;
187 for (int i = 0; i < length; i++) if (h_input[i] > FLT_ZERO) n_pos++;
188 bool pack_ok = validation(h_output_pack.data(), h_output_gpu.data(), n_pos);
189 std::printf(" pack (%d elems, %d positive): %s\n", length, n_pos, pack_ok ? "match" : "MISMATCH");
190 ok = ok && pack_ok;
191
192 // ---- Split --------------------------------------------------------------
193 cudaMemcpy(d_input, d_output, sizeof(float) * length, cudaMemcpyDeviceToDevice);
194 cudaMemset(d_output, 0, sizeof(float) * length);
195 LAUNCH(split_kernel, GRID_DIM, N_ELEM, d_output, d_input, d_predicates, d_scanned, length); // [SIM]
196 cudaDeviceSynchronize();
197
198 cudaMemcpy(h_output_gpu.data(), d_output, sizeof(float) * length, cudaMemcpyDeviceToHost);
199 split_host(h_output_host.data(), h_input.data(), length);
200 bool split_ok = validation(h_output_host.data(), h_output_gpu.data(), length);
pack (test_web_pk_packsplit.cu:189)
179 cudaDeviceSynchronize();
180
181 cudaMemcpy(h_output_gpu.data(), d_output, sizeof(float) * length, cudaMemcpyDeviceToHost);
182 // CPU reference produces a compacted prefix; unused tail is undefined, so
183 // only the first (count of positives) entries are compared.
184 std::vector<float> h_output_pack(length, 0.f);
185 pack_host(h_output_pack.data(), h_input.data(), length);
186 int n_pos = 0;
187 for (int i = 0; i < length; i++) if (h_input[i] > FLT_ZERO) n_pos++;
188 bool pack_ok = validation(h_output_pack.data(), h_output_gpu.data(), n_pos);
189 std::printf(" pack (%d elems, %d positive): %s\n", length, n_pos, pack_ok ? "match" : "MISMATCH");
190 ok = ok && pack_ok;
191
192 // ---- Split --------------------------------------------------------------
193 cudaMemcpy(d_input, d_output, sizeof(float) * length, cudaMemcpyDeviceToDevice);
194 cudaMemset(d_output, 0, sizeof(float) * length);
195 LAUNCH(split_kernel, GRID_DIM, N_ELEM, d_output, d_input, d_predicates, d_scanned, length); // [SIM]
196 cudaDeviceSynchronize();
197
198 cudaMemcpy(h_output_gpu.data(), d_output, sizeof(float) * length, cudaMemcpyDeviceToHost);
199 split_host(h_output_host.data(), h_input.data(), length);
200 bool split_ok = validation(h_output_host.data(), h_output_gpu.data(), length);
pack (test_web_pk_packsplit.cu:189)
179 cudaDeviceSynchronize();
180
181 cudaMemcpy(h_output_gpu.data(), d_output, sizeof(float) * length, cudaMemcpyDeviceToHost);
182 // CPU reference produces a compacted prefix; unused tail is undefined, so
183 // only the first (count of positives) entries are compared.
184 std::vector<float> h_output_pack(length, 0.f);
185 pack_host(h_output_pack.data(), h_input.data(), length);
186 int n_pos = 0;
187 for (int i = 0; i < length; i++) if (h_input[i] > FLT_ZERO) n_pos++;
188 bool pack_ok = validation(h_output_pack.data(), h_output_gpu.data(), n_pos);
189 std::printf(" pack (%d elems, %d positive): %s\n", length, n_pos, pack_ok ? "match" : "MISMATCH");
190 ok = ok && pack_ok;
191
192 // ---- Split --------------------------------------------------------------
193 cudaMemcpy(d_input, d_output, sizeof(float) * length, cudaMemcpyDeviceToDevice);
194 cudaMemset(d_output, 0, sizeof(float) * length);
195 LAUNCH(split_kernel, GRID_DIM, N_ELEM, d_output, d_input, d_predicates, d_scanned, length); // [SIM]
196 cudaDeviceSynchronize();
197
198 cudaMemcpy(h_output_gpu.data(), d_output, sizeof(float) * length, cudaMemcpyDeviceToHost);
199 split_host(h_output_host.data(), h_input.data(), length);
200 bool split_ok = validation(h_output_host.data(), h_output_gpu.data(), length);