Is there really a need to store (and AddRef) the clipper? The primary surface already keeps a reference to it, so you should be OK. It won't give you the increment by 2 that native has though, but I don't think that's important.
> + hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &ds, NULL);
> + if (FAILED(hr))
> + return hr;
> +
> + hr = IDirectDrawSurface_AddAttachedSurface(surface, ds);
> + if (FAILED(hr))
> + {
> + IDirectDrawSurface_Release(ds);
> + return hr;
> + }
Similarly: Is there a need to store the depth stencil? You could just release your reference after attaching it to the render target, it will stay alive anyway. (If it's just for the DeleteAttachedSurface later: Ignore it)
You have to keep ddraw alive because nothing (neither your surfaces nor your device) hold a reference to it. Same for the primary. I think it's also good to store a reference to the render target, I believe you need it to show the rendering results on the screen (The immediate mode device holds a ref too, but it's awkward to always query it from the device).
> + if (device->ref == 1 && device->z_created_internally)
> + IDirectDrawSurface_DeleteAttachedSurface(device->render_target, 0, device->depth_surface);
As mentioned on IRC this is not thread safe A lot can happen between your ref == 1 comparison and the actual InterlockedDecrement.
Wrt patch 6 (d3drm1_CreateDeviceFromClipper): It's a bit unfortunate that this is mostly a copypasted version of version 3, and the difference that actually matters is in init_device anyway. Maybe there is a nicer solution, e.g. a helper function for v1 and v3 with a version parameter.