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

enum cudaChannelFormatKind

sim only

simulator.h:2788

Functions#

Signature

Description

Availability

Location

Example

inline cudaChannelFormatDesc cudaCreateChannelDesc(int x, int y, int z, int w, cudaChannelFormatKind f)

sim only

simulator.h:2794

View

inline cudaChannelFormatDesc cudaCreateChannelDesc()

sim only

simulator.h:2814

View

inline cudaError_t cudaFreeArray(cudaArray_t a)

sim only

simulator.h:2887

View

inline cudaError_t cudaMallocArray(cudaArray_t* a, const cudaChannelFormatDesc* desc, size_t width, size_t height = 0, unsigned = 0)

sim only

simulator.h:2875

View

inline void decodeNormalized(const cudaChannelFormatDesc& d, const unsigned char* p, float out[4])

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

static cudaChannelFormatDesc get()

sim only

simulator.h:2800

static float pack(const float c[4])

sim only

simulator.h:2868

View

static float2 pack(const float c[4])

sim only

simulator.h:2870

View

static float4 pack(const float c[4])

sim only

simulator.h:2872

View

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);