@@ -585,6 +585,7 @@ struct ggml_backend_opencl_context {
585585 cl_kernel kernel_convert_block_mxfp4_trans4_ns, kernel_restore_block_mxfp4_trans4_ns;
586586 cl_kernel kernel_convert_block_q8_0, kernel_restore_block_q8_0, kernel_restore_block_q8_0_trans;
587587 cl_kernel kernel_convert_block_q6_K_noshuffle, kernel_restore_block_q6_K_noshuffle;
588+ cl_kernel kernel_convert_bf16_to_f16, kernel_convert_f16_to_bf16;
588589 cl_kernel kernel_mul_mat_q4_0_f32_8x_flat;
589590 cl_kernel kernel_convert_block_q4_0_noshuffle;
590591 cl_kernel kernel_restore_block_q4_0_noshuffle;
@@ -1175,6 +1176,8 @@ static void load_cl_kernels(ggml_backend_opencl_context *backend_ctx) {
11751176 CL_CHECK((backend_ctx->kernel_restore_block_iq4_nl = clCreateKernel(backend_ctx->program_cvt, "kernel_restore_block_iq4_nl", &err), err));
11761177 CL_CHECK((backend_ctx->kernel_convert_block_iq4_nl_noshuffle = clCreateKernel(backend_ctx->program_cvt, "kernel_convert_block_iq4_nl_noshuffle", &err), err));
11771178 CL_CHECK((backend_ctx->kernel_restore_block_iq4_nl_noshuffle = clCreateKernel(backend_ctx->program_cvt, "kernel_restore_block_iq4_nl_noshuffle", &err), err));
1179+ CL_CHECK((backend_ctx->kernel_convert_bf16_to_f16 = clCreateKernel(backend_ctx->program_cvt, "kernel_convert_bf16_to_f16", &err), err));
1180+ CL_CHECK((backend_ctx->kernel_convert_f16_to_bf16 = clCreateKernel(backend_ctx->program_cvt, "kernel_convert_f16_to_bf16", &err), err));
11781181 GGML_LOG_CONT(".");
11791182 }
11801183
@@ -5019,6 +5022,8 @@ static bool ggml_opencl_supports_op(ggml_backend_dev_t dev, const struct ggml_te
50195022 case GGML_OP_MUL_MAT:
50205023 if (op->src[0]->type == GGML_TYPE_F16) {
50215024 return true;
5025+ } else if (op->src[0]->type == GGML_TYPE_BF16) {
5026+ return true;
50225027 } else if (op->src[0]->type == GGML_TYPE_F32) {
50235028 return op->src[1]->type == GGML_TYPE_F32;
50245029 } else if (op->src[0]->type == GGML_TYPE_Q4_0 || op->src[0]->type == GGML_TYPE_Q4_1 ||
@@ -6828,6 +6833,40 @@ static void ggml_backend_opencl_buffer_set_tensor(ggml_backend_buffer_t buffer,
68286833 }
68296834#endif // GGML_OPENCL_SOA_Q
68306835
6836+ // convert bf16 to f16 and store as f16 in device buffer
6837+ if (tensor->type == GGML_TYPE_BF16) {
6838+ GGML_ASSERT(offset % sizeof(ggml_fp16_t) == 0 && size % sizeof(ggml_fp16_t) == 0
6839+ && "Offset and size must be multiples of 2 for bf16 tensors");
6840+
6841+ ggml_tensor_extra_cl * extra = (ggml_tensor_extra_cl *) tensor->extra;
6842+ GGML_ASSERT(extra);
6843+
6844+ cl_ulong n_elements = size / sizeof(ggml_fp16_t);
6845+ cl_ulong off_dst = (extra->offset + offset) / sizeof(ggml_fp16_t);
6846+
6847+ cl_int err;
6848+ cl_mem data_device = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
6849+ size, (void *) data, &err);
6850+ CL_CHECK(err);
6851+
6852+ cl_kernel kernel = backend_ctx->kernel_convert_bf16_to_f16;
6853+ CL_CHECK(clSetKernelArg(kernel, 0, sizeof(cl_mem), &data_device));
6854+ CL_CHECK(clSetKernelArg(kernel, 1, sizeof(cl_mem), &extra->data_device));
6855+ CL_CHECK(clSetKernelArg(kernel, 2, sizeof(cl_ulong), &off_dst));
6856+ CL_CHECK(clSetKernelArg(kernel, 3, sizeof(cl_ulong), &n_elements));
6857+
6858+ size_t global_work_size[] = { (size_t)CEIL_DIV(n_elements, 64)*64, 1, 1 };
6859+ size_t local_work_size[] = { 64, 1, 1 };
6860+
6861+ cl_event evt;
6862+ CL_CHECK(clEnqueueNDRangeKernel(queue, kernel, 3, NULL, global_work_size, local_work_size, 0, NULL, &evt));
6863+ CL_CHECK(clWaitForEvents(1, &evt));
6864+ CL_CHECK(clReleaseMemObject(data_device));
6865+ CL_CHECK(clReleaseEvent(evt));
6866+
6867+ return;
6868+ }
6869+
68316870 ggml_tensor_extra_cl * extra = (ggml_tensor_extra_cl *) tensor->extra;
68326871 GGML_ASSERT(extra);
68336872
@@ -7676,6 +7715,41 @@ static void ggml_backend_opencl_buffer_get_tensor(ggml_backend_buffer_t buffer,
76767715 }
76777716#endif // GGML_OPENCL_SOA_Q
76787717
7718+ if (tensor->type == GGML_TYPE_BF16) {
7719+ GGML_ASSERT(offset % sizeof(ggml_fp16_t) == 0 && size % sizeof(ggml_fp16_t) == 0
7720+ && "Offset and size must be multiples of 2 for bf16 tensors");
7721+
7722+ ggml_tensor_extra_cl * extra = (ggml_tensor_extra_cl *) tensor->extra;
7723+ GGML_ASSERT(extra);
7724+
7725+ cl_ulong n_elements = size / sizeof(ggml_fp16_t);
7726+ cl_ulong off_src = (extra->offset + tensor->view_offs + offset) / sizeof(ggml_fp16_t);
7727+
7728+ cl_int err;
7729+ cl_mem data_device = clCreateBuffer(context, CL_MEM_READ_WRITE, size, NULL, &err);
7730+ CL_CHECK(err);
7731+
7732+ cl_kernel kernel = backend_ctx->kernel_convert_f16_to_bf16;
7733+ CL_CHECK(clSetKernelArg(kernel, 0, sizeof(cl_mem), &extra->data_device));
7734+ CL_CHECK(clSetKernelArg(kernel, 1, sizeof(cl_ulong), &off_src));
7735+ CL_CHECK(clSetKernelArg(kernel, 2, sizeof(cl_mem), &data_device));
7736+ CL_CHECK(clSetKernelArg(kernel, 3, sizeof(cl_ulong), &n_elements));
7737+
7738+ size_t global_work_size[] = { (size_t)CEIL_DIV(n_elements, 64)*64, 1, 1 };
7739+ size_t local_work_size[] = { 64, 1, 1 };
7740+
7741+ cl_event evt;
7742+ CL_CHECK(clEnqueueNDRangeKernel(queue, kernel, 3, NULL, global_work_size, local_work_size, 0, NULL, &evt));
7743+ CL_CHECK(clWaitForEvents(1, &evt));
7744+ CL_CHECK(clReleaseEvent(evt));
7745+
7746+ CL_CHECK(clEnqueueReadBuffer(
7747+ queue, data_device, CL_TRUE, 0, size, data, 0, NULL, NULL));
7748+ CL_CHECK(clReleaseMemObject(data_device));
7749+
7750+ return;
7751+ }
7752+
76797753 ggml_tensor_extra_cl * extra = (ggml_tensor_extra_cl *) tensor->extra;
76807754
76817755 CL_CHECK(clEnqueueReadBuffer(
@@ -8165,6 +8239,7 @@ static void ggml_cl_copy_to_contiguous(ggml_backend_t backend, const ggml_tensor
81658239 kernel = backend_ctx->kernel_cpy_f32_f32;
81668240 break;
81678241 case GGML_TYPE_F16:
8242+ case GGML_TYPE_BF16: // stored as f16 on device
81688243 kernel = backend_ctx->kernel_cpy_f16_f16;
81698244 break;
81708245 default:
@@ -11125,7 +11200,8 @@ static bool ggml_cl_can_use_adreno_xmem_gemm_f16_f32(
1112511200 if (backend_ctx->gpu_family != GPU_FAMILY::ADRENO) {
1112611201 return false;
1112711202 }
11128- if (src0->type != GGML_TYPE_F16 || src1->type != GGML_TYPE_F32 || dst->type != GGML_TYPE_F32) {
11203+ if ((src0->type != GGML_TYPE_F16 && src0->type != GGML_TYPE_BF16) ||
11204+ src1->type != GGML_TYPE_F32 || dst->type != GGML_TYPE_F32) {
1112911205 return false;
1113011206 }
1113111207 if (!ggml_is_contiguous(src0) || !ggml_is_contiguous(src1) || !ggml_is_contiguous(dst)) {
@@ -12843,7 +12919,8 @@ static void ggml_cl_mul_mat(ggml_backend_t backend, const ggml_tensor * src0, co
1284312919 GGML_ASSERT(dst);
1284412920 GGML_ASSERT(dst->extra);
1284512921
12846- const enum ggml_type src0t = src0->type;
12922+ // bf16 is stored as f16 on device
12923+ const enum ggml_type src0t = (src0->type == GGML_TYPE_BF16) ? GGML_TYPE_F16 : src0->type;
1284712924 const enum ggml_type src1t = src1->type;
1284812925
1284912926 ggml_backend_opencl_context *backend_ctx = (ggml_backend_opencl_context *)backend->context;
0 commit comments